2008-09-20 20 views
383

अक्षम करें आउटपुट बफरिंग sys.stdout के लिए पाइथन के दुभाषिया में डिफ़ॉल्ट रूप से सक्षम है?आउटपुट बफरिंग

यदि उत्तर सकारात्मक है, तो इसे अक्षम करने के सभी तरीके क्या हैं?

सुझाव अब तक:

  1. उपयोग -u कमांड लाइन स्विच
  2. लपेटें sys.stdout एक वस्तु flushes उसके बाद हर लिखने में
  3. सेट PYTHONUNBUFFERED env var
  4. sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)

क्या कुछ वैश्विक फ्लैस सेट करने का कोई और तरीका है जी sys/sys.stdout निष्पादन के दौरान प्रोग्रामेटिक रूप से?

+0

'पायथन 3 में प्रिंट 'के लिए, देखें [इस उत्तर] (http://stackoverflow.com/a/14729823/918959)। –

+0

मुझे लगता है कि '-u' की कमी यह है कि यह संकलित बाइटकोड के लिए या' __main __। Py' फ़ाइल के साथ प्रविष्टि बिंदु के रूप में ऐप्स के लिए काम नहीं करेगा। – akhan

उत्तर

329

Magnus Lycka answer on a mailing list से:

You can skip buffering for a whole python process using "python -u" (or#!/usr/bin/env python -u etc) or by setting the environment variable PYTHONUNBUFFERED.

You could also replace sys.stdout with some other stream like wrapper which does a flush after every call.

class Unbuffered(object): 
    def __init__(self, stream): 
     self.stream = stream 
    def write(self, data): 
     self.stream.write(data) 
     self.stream.flush() 
    def writelines(self, datas): 
     self.stream.writelines(datas) 
     self.stream.flush() 
    def __getattr__(self, attr): 
     return getattr(self.stream, attr) 

import sys 
sys.stdout = Unbuffered(sys.stdout) 
print 'Hello' 
+62

मूल sys.stdout अभी भी sys .__ stdout__ के रूप में उपलब्ध है। बस आपको इसकी आवश्यकता होने पर =) –

+0

यह समाधान जो मैंने उपयोग किया था जब मैं मुद्रित बयानों के साथ समस्याओं में भाग गया। एक जादू की तरह काम किया। – Ryan

+23

'#!/Usr/bin/env python -u' काम नहीं करता !! देखें [यहां] (http://stackoverflow.com/q/3306518/674039) – wim

35

हाँ, यह है।

आप इसे "-u" स्विच के साथ कमांडलाइन पर अक्षम कर सकते हैं।

वैकल्पिक रूप से, आप हर लिखने पर sys.stdout पर() .flush फोन (या किसी वस्तु है कि इस के उपयोग से लपेट)

+0

सुंदर। धन्यवाद। –

8

हाँ, यह डिफ़ॉल्ट रूप से सक्षम हो सकता है। आप पाइथन को कॉल करते समय कमांड लाइन पर -u विकल्प का उपयोग करके इसे अक्षम कर सकते हैं।

4

एक तरह से unbuffered उत्पादन प्राप्त करने के लिए sys.stderrsys.stdout के बजाय या बस कॉल करने के लिए sys.stdout.flush() उपयोग करने के लिए स्पष्ट रूप से होने के लिये एक लिखने के लिए मजबूर होगा।

आप आसानी करके मुद्रित सब कुछ अनुप्रेषित सकता है:

import sys; sys.stdout = sys.stderr 
print "Hello World!" 

या एक खास print बयान लिए सिर्फ पुनर्निर्देशित करने के:

print >>sys.stderr, "Hello World!" 

तुम सिर्फ कर सकते हैं stdout रीसेट करने के:

sys.stdout = sys.__stdout__ 
+1

यह तब बहुत भ्रमित हो सकता है जब आप बाद में मानक पुनर्निर्देशन का उपयोग करके आउटपुट कैप्चर करने का प्रयास करते हैं, और पाते हैं कि आप कुछ भी कैप्चर नहीं कर रहे हैं! पी। आपका __stdout__ बोल्ड और सामान हो रहा है। – freespace

+1

चुनिंदा मुद्रण करने के बारे में एक बड़ी सावधानी यह है कि यह लाइनों को जगह से बाहर होने का कारण बनता है, इसलिए जब तक आपके पास टाइमस्टैम्प भी न हो, यह बहुत भ्रमित हो सकता है। – haridsv

3

आप एक unbuffered फ़ाइल बना सकते हैं और sys.stdou को यह फ़ाइल असाइन कर सकते हैं टी।

import sys 
myFile= open("a.log", "w", 0) 
sys.stdout= myFile 

आप सिस्टम-आपूर्ति वाले स्टडआउट को जादुई रूप से बदल नहीं सकते हैं; चूंकि यह ओएस द्वारा आपके पायथन कार्यक्रम की आपूर्ति की जाती है।

69
# reopen stdout file descriptor with write mode 
# and 0 as the buffer size (unbuffered) 
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0) 

क्रेडिट: "सेबेस्टियन", कहीं पाइथन मेलिंग सूची पर।

+14

यह अब पायथन 3 में काम नहीं करता है, पीईपी 3116 देखें। – sorin

+0

@ सोरीन: हाँ यह करता है। कृपया अपने दावे की व्याख्या करें। –

+19

पायथन 3 पर उपर्युक्त रेखा अपवाद फेंक देगी: 'ValueError: unbuffered टेक्स्ट I/O' नहीं हो सकता है। – sorin

4

आप फ़ाइल फ्लैग इन-फ्लाई को बदलने के लिए fcntl का भी उपयोग कर सकते हैं।

fl = fcntl.fcntl(fd.fileno(), fcntl.F_GETFL) 
fl |= os.O_SYNC# or os.O_DSYNC (if you don't care the file timestamp updates) 
fcntl.fcntl(fd.fileno(), fcntl.F_SETFL, fl) 
+1

यह * निक्स केवल नहीं है? –

+0

आह ... यह शायद सही है। – jimx

+1

विंडोज़ समकक्ष है: http://stackoverflow.com/questions/881696/unbuffered-stdout-in-python-as-in-python-u-from-within-the-program/881751#881751 – Tobu

11
def disable_stdout_buffering(): 
    # Appending to gc.garbage is a way to stop an object from being 
    # destroyed. If the old sys.stdout is ever collected, it will 
    # close() stdout, which is not good. 
    gc.garbage.append(sys.stdout) 
    sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0) 

# Then this will give output in the correct order: 
disable_stdout_buffering() 
print "hello" 
subprocess.call(["echo", "bye"]) 

वर्ष sys बचत के बिना।stdout, disable_stdout_buffering() idempotent नहीं है, और कई कॉल इस तरह एक त्रुटि में परिणाम होगा:

Traceback (most recent call last): 
    File "test/buffering.py", line 17, in <module> 
    print "hello" 
IOError: [Errno 9] Bad file descriptor 
close failed: [Errno 9] Bad file descriptor 

एक और संभावना है:

def disable_stdout_buffering(): 
    fileno = sys.stdout.fileno() 
    temp_fd = os.dup(fileno) 
    sys.stdout.close() 
    os.dup2(temp_fd, fileno) 
    os.close(temp_fd) 
    sys.stdout = os.fdopen(fileno, "w", 0) 

(gc.garbage को जोड़ना इतना अच्छा नहीं है । विचार है क्योंकि यह जहां unfreeable चक्र डाल पाने के है, और आप उन लोगों के लिए जाँच करने के लिए चाहते हो सकता है)

+2

यदि पुराना 'stdout' अभी भी' sys .__ stdout__' पर रहता है जैसा कि कुछ ने सुझाव दिया है, कचरा चीज आवश्यक नहीं होगी, है ना? हालांकि यह एक अच्छा चाल है। –

4

संस्करण जो क्रैश (कम से कम Win32 पर बिना काम करता है, अजगर 2.7, 0.12 IPython) फिर आगे चलकर बुलाया (कई बार):

def DisOutBuffering(): 
    if sys.stdout.name == '<stdout>': 
     sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0) 

    if sys.stderr.name == '<stderr>': 
     sys.stderr = os.fdopen(sys.stderr.fileno(), 'w', 0) 
+0

क्या आप वाकई buffered नहीं हैं? – quantum

+1

क्या आपको नाम sy विशेषता वाले प्रतिस्थापन ऑब्जेक्ट पर भरोसा करने के बजाय 'sys.stdout sys .__ stdout__' की जांच करनी चाहिए? – leewz

+0

यह बहुत अच्छा काम करता है अगर बंदूकधारक किसी कारण से PYTHONUNBUFFERED का सम्मान नहीं कर रहा है। –

52

मैं नहीं बल्कि How to flush output of Python print? में या Python's print function that flushes the buffer when it's called? में मेरा उत्तर डाल सकता है, लेकिन जब से वे इस एक के डुप्लिकेट के रूप में चिह्नित किया गया था (मैं क्या इस बात से सहमत नहीं है), मैं इसे यहाँ जवाब देंगे।

अजगर 3.3 प्रिंट() कीवर्ड तर्क "फ्लश" (see documentation) का समर्थन करता है के बाद से:

print('Hello World!', flush=True) 
3

(मैं एक टिप्पणी पोस्ट किया है, लेकिन यह किसी भी तरह खो गया तो, फिर से :)

  1. जैसा कि मैंने देखा, सीपीथॉन (कम से कम लिनक्स पर) आउटपुट कहां जाता है इसके आधार पर अलग-अलग व्यवहार करता है। यदि यह एक tty पर जाता है, तो प्रत्येक

    के बाद आउटपुट फ़्लश हो जाता है यदि यह पाइप/प्रक्रिया में जाता है, तो यह buffered है और आप ऊपर दिए गए flush() आधारित समाधान या -u विकल्प का उपयोग कर सकते हैं।

  2. थोड़ा उत्पादन बफरिंग से संबंधित:
    आप में कार्यान्वयन के लिए

    for line in sys.stdin:
    ...

तो

साथ निवेश में लाइनों पर पुनरावृति तो CPython थोड़ी देर के लिए इनपुट एकत्र करेगा और फिर इनपुट लाइनों के समूह के लिए लूप बॉडी निष्पादित करेगा। यदि आपकी स्क्रिप्ट प्रत्येक इनपुट लाइन के लिए आउटपुट लिखने वाली है, तो यह आउटपुट बफरिंग की तरह लग सकती है लेकिन यह वास्तव में बैचिंग है, और इसलिए flush() आदि में से कोई भी तकनीक इसकी मदद नहीं करेगी। दिलचस्प बात यह है कि आपके पास यह व्यवहार pypy में नहीं है। इससे बचने के लिए आप

while True: line=sys.stdin.readline()
...

+0

[यहां आपकी टिप्पणी है] (http://stackoverflow.com/questions/107705/python-output-buffering/107717#comment24604506_107717)। यह पुराने पायथन संस्करणों पर एक बग हो सकता है। क्या आप उदाहरण कोड प्रदान कर सकते हैं? कुछ ['sys.stdin' में लाइन के लिए] (http://ideone.com/TzHwlX) बनाम [' इनर लाइन में लाइन के लिए (sys.stdin.readline, "") '] (http: // ideone। com/mMxn09) – jfs

+0

sys.stdin में लाइन के लिए: प्रिंट ("रेखा:" + रेखा); sys.stdout.flush() – tzp

+0

ऐसा लगता है [रीड-फॉर बग] (https://bugs.python.org/issue3907)। यह केवल पायथन 2 पर होना चाहिए और यदि stdin एक पाइप है। मेरी पिछली टिप्पणी में कोड इस मुद्दे को प्रदर्शित करता है ('sys.stdin' में लाइन के लिए देरी प्रतिक्रिया प्रदान करता है) – jfs

7

अजगर 2.6, 2.7 में निम्नलिखित काम करता है, और 3.2 का उपयोग कर सकते हैं:

import os 
import sys 
buf_arg = 0 
if sys.version_info[0] == 3: 
    os.environ['PYTHONUNBUFFERED'] = '1' 
    buf_arg = 1 
sys.stdout = os.fdopen(sys.stdout.fileno(), 'a+', buf_arg) 
sys.stderr = os.fdopen(sys.stderr.fileno(), 'a+', buf_arg) 
+0

इसे दो बार चलाएं और यह विंडोज़ पर दुर्घटनाग्रस्त हो जाता है :-) –

+0

@MichaelClerx Mmm hmm, हमेशा अपनी फ़ाइलों को बंद करना याद रखें xD। –

4

तुम भी stdbuf उपयोगिता के साथ अजगर चला सकते हैं:

stdbuf -oL python <script>

10

यह टी संबंधित है ओ Cristóvão डी Sousa जवाब, लेकिन मैं अभी तक टिप्पणी नहीं कर सका।

हमेशा unbuffered उत्पादन करने के क्रम में अजगर 3 की flush कीवर्ड तर्क का उपयोग करने का एक सीधी-सपाट तरीका है:

import functools 
print = functools.partial(print, flush=True) 

बाद में, प्रिंट हमेशा सीधे उत्पादन फ्लश (flush=False को छोड़कर दिया हुआ है)।

ध्यान दें, (क) है कि इस सवाल का जवाब केवल आंशिक रूप से यह सब उत्पादन रीडायरेक्ट नहीं करता है के रूप में। लेकिन मुझे लगता है कि print अजगर में stdout/stderr के उत्पादन बनाने के लिए सबसे आम तरीका है, इसलिए इन 2 लाइनों शायद उपयोग के मामलों के सबसे को कवर किया।

नोट (ख) है कि यह केवल मॉड्यूल/लिपि जहां आप इसे परिभाषित में काम करता है। मॉड्यूल लिखते समय यह अच्छा हो सकता है क्योंकि यह sys.stdout के साथ गड़बड़ नहीं करता है।

अजगर 2flush तर्क प्रदान नहीं करता है, लेकिन आप एक अजगर 3-प्रकार print समारोह के रूप में यहाँ https://stackoverflow.com/a/27991478/3734258 वर्णित का अनुकरण कर सकते हैं।

+1

सिवाय इसके कि Python2 में कोई 'फ्लश' kwarg नहीं है। – o11c

+0

@ ओ 11 सी, हाँ आप सही हैं। मुझे यकीन था कि मैंने इसका परीक्षण किया लेकिन किसी भी तरह से मैं उलझन में था (: मैंने अपना जवाब संशोधित किया, उम्मीद है कि यह ठीक है। धन्यवाद! – ciem

1

ऐसा नहीं है कि flush कॉल एक के साथ sys.stdout की केवलwrite विधि ओवरराइड करने के लिए संभव है। सुझाए गए विधि कार्यान्वयन नीचे है।

w तर्क के
def write_flush(args, w=stdout.write): 
    w(args) 
    stdout.flush() 

डिफ़ॉल्ट मूल्य मूल write विधि संदर्भ रखेंगे।write_flushबाद परिभाषित किया गया है, मूल write अधिरोहित जा सकता है।

stdout.write = write_flush 

कोड मानता है कि इस तरह से stdoutfrom sys import stdout आयात किया जाता है।

संबंधित मुद्दे