Saya selalu kagum / frustrasi dengan berapa lama waktu yang dibutuhkan untuk hanya output ke terminal dengan pernyataan cetak. Setelah beberapa logging lambat lambat baru-baru ini saya memutuskan untuk melihatnya dan cukup terkejut menemukan bahwa hampir semua waktu yang dihabiskan menunggu terminal untuk memproses hasilnya.
Bisakah menulis ke stdout dipercepat entah bagaimana?
Saya menulis sebuah skrip (' print_timer.py
' di bagian bawah pertanyaan ini) untuk membandingkan waktu ketika menulis 100k baris ke stdout, ke file, dan dengan stdout dialihkan ke /dev/null
. Berikut ini adalah hasil waktunya:
$ python print_timer.py
this is a test
this is a test
<snipped 99997 lines>
this is a test
-----
timing summary (100k lines each)
-----
print :11.950 s
write to file (+ fsync) : 0.122 s
print with stdout = /dev/null : 0.050 s
Wow. Untuk memastikan python tidak melakukan sesuatu di balik layar seperti mengenali bahwa saya menetapkan ulang stdout ke / dev / null atau sesuatu, saya melakukan pengalihan di luar skrip ...
$ python print_timer.py > /dev/null
-----
timing summary (100k lines each)
-----
print : 0.053 s
write to file (+fsync) : 0.108 s
print with stdout = /dev/null : 0.045 s
Jadi ini bukan trik python, itu hanya terminal. Saya selalu tahu membuang output ke / dev / null mempercepat, tetapi tidak pernah mengira itu signifikan!
Ini mengejutkan saya betapa lambatnya tty. Bagaimana bisa menulis ke disk fisik adalah CARA yang lebih cepat daripada menulis ke "layar" (mungkin semua-RAM op), dan secara efektif secepat hanya membuang ke sampah dengan / dev / null?
Tautan ini berbicara tentang bagaimana terminal akan memblokir I / O sehingga dapat "mengurai [input], memperbarui buffer frame-nya, berkomunikasi dengan server X untuk menggulir jendela dan sebagainya" ... tapi saya tidak sepenuhnya mendapatkannya. Apa yang bisa memakan waktu lama?
Saya berharap tidak ada jalan keluar (pendeknya implementasi tty yang lebih cepat?) Tetapi saya akan bertanya.
UPDATE: setelah membaca beberapa komentar saya bertanya-tanya seberapa besar dampak ukuran layar saya pada waktu cetak, dan memang ada beberapa signifikansi. Angka-angka yang sangat lambat di atas adalah dengan terminal Gnome saya meledak hingga 1920x1200. Jika saya menguranginya sangat kecil saya dapatkan ...
-----
timing summary (100k lines each)
-----
print : 2.920 s
write to file (+fsync) : 0.121 s
print with stdout = /dev/null : 0.048 s
Itu tentu lebih baik (~ 4x), tetapi tidak mengubah pertanyaan saya. Itu hanya menambah pertanyaan saya karena saya tidak mengerti mengapa rendering layar terminal harus memperlambat penulisan aplikasi ke stdout. Mengapa program saya harus menunggu rendering layar untuk melanjutkan?
Apakah semua aplikasi terminal / tty tidak dibuat sama? Saya belum bereksperimen. Menurut saya benar-benar seperti terminal harus dapat buffer semua data yang masuk, parse / render itu tak terlihat, dan hanya membuat potongan terbaru yang terlihat dalam konfigurasi layar saat ini pada frame rate yang masuk akal. Jadi jika saya dapat menulis + fsync ke disk dalam ~ 0,1 detik, terminal harus dapat menyelesaikan operasi yang sama dalam sesuatu dari urutan itu (dengan mungkin beberapa pembaruan layar saat melakukannya).
Saya masih agak berharap ada pengaturan tty yang dapat diubah dari sisi aplikasi untuk membuat perilaku ini lebih baik untuk programmer. Jika ini benar-benar masalah aplikasi terminal, maka ini mungkin bahkan bukan milik StackOverflow?
Apa yang saya lewatkan?
Berikut adalah program python yang digunakan untuk menghasilkan waktu:
import time, sys, tty
import os
lineCount = 100000
line = "this is a test"
summary = ""
cmd = "print"
startTime_s = time.time()
for x in range(lineCount):
print line
t = time.time() - startTime_s
summary += "%-30s:%6.3f s\n" % (cmd, t)
#Add a newline to match line outputs above...
line += "\n"
cmd = "write to file (+fsync)"
fp = file("out.txt", "w")
startTime_s = time.time()
for x in range(lineCount):
fp.write(line)
os.fsync(fp.fileno())
t = time.time() - startTime_s
summary += "%-30s:%6.3f s\n" % (cmd, t)
cmd = "print with stdout = /dev/null"
sys.stdout = file(os.devnull, "w")
startTime_s = time.time()
for x in range(lineCount):
fp.write(line)
t = time.time() - startTime_s
summary += "%-30s:%6.3f s\n" % (cmd, t)
print >> sys.stderr, "-----"
print >> sys.stderr, "timing summary (100k lines each)"
print >> sys.stderr, "-----"
print >> sys.stderr, summary