मैं हमेशा से चकित / निराश रहा हूं कि प्रिंट स्टेटमेंट के साथ टर्मिनल पर बस आउटपुट करने में कितना समय लगता है। कुछ हालिया दर्दनाक धीमी लॉगिंग के बाद मैंने इसे देखने का फैसला किया और यह जानकर काफी आश्चर्यचकित हुआ कि लगभग सभी समय टर्मिनल के परिणामों के लिए इंतजार कर रहा है।
क्या स्टडआउट को लिखना किसी भी तरह से लिखा जा सकता है?
मैंने print_timer.py
100k लाइन्स को stdout, फाइल करने के लिए, और stdout के साथ रीडायरेक्ट करने के लिए 100k लाइन्स लिखते समय टाइमिंग की तुलना करने के लिए एक स्क्रिप्ट (' ' इस सवाल के नीचे) लिखी /dev/null
। यहाँ समय परिणाम है:
$ 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
वाह। यह सुनिश्चित करने के लिए कि अजगर पर्दे के पीछे से कुछ नहीं कर रहा है, जैसे कि मैं पहचानता हूं कि मैंने stdout को / dev / null या कुछ और करने के लिए आश्वस्त किया था, मैंने स्क्रिप्ट के बाहर पुनर्निर्देशन किया ...
$ 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
तो यह एक अजगर चाल नहीं है, यह सिर्फ टर्मिनल है। मुझे हमेशा पता था कि डंपिंग आउटपुट / देव / अशक्त चीज़ों के लिए आउटपुट है, लेकिन यह कभी नहीं सोचा कि यह महत्वपूर्ण था!
यह मुझे याद दिलाता है कि टैटी कितनी धीमी है। यह कैसे हो सकता है कि भौतिक डिस्क पर लिखना "स्क्रीन" (संभवतः एक ऑल-रैम ऑप) लिखने की तुलना में तेज़ है, और प्रभावी रूप से उतनी ही तेजी से है जितना कि कचरा / देव / नल के साथ कचरा डंप करना?
यह लिंक इस बारे में बात करता है कि टर्मिनल I / O को कैसे अवरुद्ध करेगा ताकि यह "इनपुट को पार्स कर सके ", इसके फ्रेम बफर को अपडेट करें, विंडो को स्क्रॉल करने के लिए X सर्वर से संवाद करें और इसी तरह " ... लेकिन मैं नहीं पूरी तरह से प्राप्त करें। इतनी देर क्या हो सकती है?
मुझे उम्मीद है कि कोई रास्ता नहीं निकलेगा (तेज ट्टी कार्यान्वयन की कमी?) लेकिन आंकड़ा मैं वैसे भी पूछूंगा।
अद्यतन: कुछ टिप्पणियों को पढ़ने के बाद मैंने सोचा कि मेरे स्क्रीन के आकार का प्रिंट समय पर वास्तव में कितना प्रभाव है, और इसका कुछ महत्व है। ऊपर वास्तव में धीमी संख्या में मेरे गनोम टर्मिनल 1920x1200 तक उड़ा दिए गए हैं। अगर मैं इसे बहुत छोटा कर दूं तो मुझे ...
-----
timing summary (100k lines each)
-----
print : 2.920 s
write to file (+fsync) : 0.121 s
print with stdout = /dev/null : 0.048 s
यह निश्चित रूप से बेहतर है (~ 4x), लेकिन मेरा सवाल नहीं बदलता है। यह केवल मेरे सवाल में जोड़ता है क्योंकि मुझे समझ में नहीं आता है कि टर्मिनल स्क्रीन रेंडरिंग को स्टैडआउट को लिखने वाले एप्लिकेशन को धीमा क्यों करना चाहिए। मेरे कार्यक्रम को जारी रखने के लिए स्क्रीन रेंडरिंग की प्रतीक्षा करने की आवश्यकता क्यों है?
क्या सभी टर्मिनल / tty ऐप्स समान नहीं बनाए गए हैं? मुझे अभी प्रयोग करना बाकी है। यह वास्तव में मुझे लगता है कि एक टर्मिनल को आने वाले सभी डेटा को बफर करने में सक्षम होना चाहिए, इसे अदृश्य रूप से पार्स / रेंडर करना चाहिए, और केवल सबसे हालिया रंक को प्रस्तुत करना चाहिए जो एक समझदार फ्रेम दर पर वर्तमान स्क्रीन कॉन्फ़िगरेशन में दिखाई देता है। इसलिए अगर मैं ~ 0.1 सेकंड में डिस्क पर fsync लिख सकता हूं, तो एक टर्मिनल को उसी ऑर्डर में से कुछ में उसी ऑपरेशन को पूरा करने में सक्षम होना चाहिए (ऐसा करते समय शायद कुछ स्क्रीन अपडेट के साथ)।
मैं अभी भी उम्मीद कर रहा हूं कि एक ट्टी सेटिंग है जिसे प्रोग्रामर के लिए इस व्यवहार को बेहतर बनाने के लिए एप्लिकेशन पक्ष से बदला जा सकता है। यदि यह कड़ाई से एक टर्मिनल आवेदन मुद्दा है, तो यह शायद StackOverflow पर भी नहीं है?
मैं क्या खो रहा हूँ?
यहाँ समय उत्पन्न करने के लिए अजगर कार्यक्रम का उपयोग किया जाता है:
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