आउटपुट बफ़रिंग अक्षम करें


532

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

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

अब तक के सुझाव:

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

क्या निष्पादन के दौरान sys/ sys.stdoutकार्यक्रम में कुछ वैश्विक ध्वज सेट करने का कोई अन्य तरीका है ?


7
पायथन 3 में `प्रिंट 'के लिए, यह उत्तर देखें ।
अंती हापला

1
मुझे लगता -uहै कि इसका एक दोष यह है कि यह संकलित बाईटेकोड के लिए या __main__.pyएंट्री पॉइंट के रूप में एक फाइल के साथ काम नहीं करेगा ।
अखन

पूर्ण CPython आरंभीकरण तर्क यहाँ है: github.com/python/cpython/blob/v3.8.2/Python/…
बेनी चेर्नियाव्स्की-पास्किन

जवाबों:


443

मेलिंग सूची में मैग्नस लिक्का जवाब से :

आप "python -u" (या #! / Usr / bin / env python -u आदि) का उपयोग करके या पर्यावरण चर PYTHONUNBUFFEDED सेट करके पूरी अजगर प्रक्रिया के लिए बफरिंग छोड़ सकते हैं।

आप sys.stdout को रैपर जैसे किसी अन्य स्ट्रीम से भी बदल सकते हैं जो कि हर कॉल के बाद फ्लश करता है।

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'

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

40
#!/usr/bin/env python -uकाम नहीं करता है !! देखने के लिए यहाँ
विम

6
__getattr__सिर्फ विरासत से बचने के लिए ?!
व्लादिमीर केलशेव

32
कुछ सिरदर्द को बचाने के लिए कुछ नोट: जैसा कि मैंने देखा, आउटपुट बफ़रिंग अलग तरीके से काम करता है, अगर आउटपुट टटी या किसी अन्य प्रक्रिया या पाइप पर जाता है। यदि यह टटी पर जाता है, तो इसे प्रत्येक \ n के बाद फ्लश किया जाता है , लेकिन एक पाइप में यह बफर होता है। बाद के मामले में आप इन फ्लशिंग समाधानों का उपयोग कर सकते हैं। Cpython में (pypy में नहीं !!!): यदि आप sys.stdin में लाइन के साथ इनपुट पर पुनरावृति करते हैं : ... तो लूप के शरीर को चलाने से पहले लूप के लिए कई पंक्तियों को एकत्रित करेगा। यह बफरिंग की तरह व्यवहार करेगा, हालांकि यह बैचिंग है। इसके बजाय, सच
tzp

5
@tzp: आप लूप के iter()बजाय उपयोग कर सकते हैं :। आपको पायथन 3 पर इसकी आवश्यकता नहीं है, जहाँ जितनी जल्दी हो सके। whilefor line in iter(pipe.readline, ''):for line in pipe:
JFS

122

मैं नहीं बल्कि प्रिंट समारोह के उत्पादन में कैसे अपना जवाब डालूं? या पायथन के प्रिंट फंक्शन में जो बफर को फ्लश करता है जब इसे कहा जाता है? , लेकिन जब से उन्हें इस एक के डुप्लिकेट के रूप में चिह्नित किया गया था (जो मैं सहमत नहीं हूं), मैं इसका जवाब यहां दूंगा।

पायथन 3.3 के बाद से, प्रिंट () कीवर्ड तर्क "फ्लश" का समर्थन करता है ( प्रलेखन देखें ):

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

77
# reopen stdout file descriptor with write mode
# and 0 as the buffer size (unbuffered)
import io, os, sys
try:
    # Python 3, open as binary, then wrap in a TextIOWrapper with write-through.
    sys.stdout = io.TextIOWrapper(open(sys.stdout.fileno(), 'wb', 0), write_through=True)
    # If flushing on newlines is sufficient, as of 3.7 you can instead just call:
    # sys.stdout.reconfigure(line_buffering=True)
except TypeError:
    # Python 2
    sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)

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


Python3 में आप बस एक फ्लशिंग के साथ प्रिंट फ़ंक्शन के नाम को ओवरराइड कर सकते हैं। हालांकि यह एक गंदा चाल है!
मेवोप्लप

16
@meawoppl: आप पायथन 3.3 के बाद flush=Trueसे print()कार्य करने के लिए पैरामीटर पास कर सकते हैं ।
JFS

प्रतिक्रिया दिखाने के लिए संपादन प्रतिक्रिया अजगर के हाल के संस्करण में मान्य नहीं है
माइक

दोनों os.fdopen(sys.stdout.fileno(), 'wb', 0)( bबाइनरी के लिए ध्यान दें ) और flush=Trueमेरे लिए 3.6.4 में काम करते हैं। हालाँकि, यदि आप किसी अन्य स्क्रिप्ट को शुरू करने के लिए उपप्रकार का उपयोग कर रहे हैं , तो सुनिश्चित करें कि आपने निर्दिष्ट किया है python3, यदि आपके पास अजगर के कई उदाहरण स्थापित हैं।
not2qubit

1
@ not2qubit: यदि आप उपयोग करते os.fdopen(sys.stdout.fileno(), 'wb', 0)हैं तो आप बाइनरी फ़ाइल ऑब्जेक्ट के साथ समाप्त होते हैं, TextIOस्ट्रीम नहीं । आपको TextIOWrapperमिक्स में एक जोड़ना होगा ( write_throughसभी बफ़र्स को खत्म करने में सक्षम बनाने के लिए , या line_buffering=Trueकेवल नईलाइन्स पर फ्लश करने के लिए उपयोग करना होगा)।
मार्टिन पीटर्स

55

हाँ यही है।

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

वैकल्पिक रूप से, आप प्रत्येक लेखन पर sys.stdout पर .flush () कॉल कर सकते हैं (या इसे स्वचालित रूप से किसी ऑब्जेक्ट के साथ लपेटें)


19

यह क्रिस्टोवो डी। सूसा के जवाब से संबंधित है, लेकिन मैं अभी तक टिप्पणी नहीं कर सकता।

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

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

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

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

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

पायथन 2flush तर्क प्रदान नहीं करता है, लेकिन आप printयहाँ वर्णित https://stackoverflow.com/a/27991478/3734258 पायथन 3-प्रकार के फ़ंक्शन का अनुकरण कर सकते हैं ।


1
सिवाय इसके कि flushअजगर 2 में कोई कंवर नहीं है।
o11c

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

14
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 () निष्क्रिय नहीं है, और कई कॉल इस तरह एक त्रुटि के परिणामस्वरूप होंगे:

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 में शामिल होना इतना अच्छा विचार नहीं है क्योंकि यह वह जगह है जहाँ अप्राप्य चक्र मिलते हैं, और आप उन लोगों के लिए जाँच कर सकते हैं।)


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

1
@ फेडेरिको के जवाब के साथ, यह पायथन 3 के साथ काम नहीं करेगा, क्योंकि यह ValueError: can't have unbuffered text I/Oकॉल करते समय अपवाद को फेंक देगा print()
gbmhunter

आपका "एक और संभावना" सबसे मजबूत समाधान की तरह पहले लगता है, लेकिन दुर्भाग्य से यह इस मामले में एक दौड़ की स्थिति से ग्रस्त है कि आपके sys.stdout.close () और आपके os.dup2 (temp.fd, fileno) से पहले एक और थ्रेड कॉल खुले () )। मुझे यह पता चला जब मैंने थ्रेडसानाइज़र के तहत आपकी तकनीक का उपयोग करने की कोशिश की, जो वास्तव में ऐसा करता है। असफलता को इस तथ्य से जोर से बनाया जाता है कि जब यह खुला () के साथ दौड़ता है तो ड्यूस 2 () EBUSY के साथ विफल हो जाता है; देखें stackoverflow.com/questions/23440216/…
डॉन हैच

13

पायथन 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)

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

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

रसियन 9 पर पायथन 3.5 मुझे OSError: [Errno 29] Illegal seekलाइन के लिए देता हैsys.stdout = os.fdopen(sys.stdout.fileno(), 'a+', buf_arg)
sdbbs

12

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


7

आप stdbuf उपयोगिता के साथ पायथन भी चला सकते हैं :

stdbuf -oL python <script>


2
लाइन बफरिंग ( -oLसक्षम बनाता है) अभी भी बफरिंग है - f / e stackoverflow.com/questions/58416853/… देखें , यह पूछते हुए कि end=''आउटपुट क्यों अब तुरंत प्रदर्शित नहीं होता है।
चार्ल्स डफी

यह सच है, लेकिन लाइन बफ़रिंग डिफ़ॉल्ट (एक ट्टी के साथ) है, तो क्या यह कोड लिखने के लिए समझ में आता है कि आउटपुट पूरी तरह से अप्रभावित है - शायद यह स्पष्ट रूप से बेहतर है print(..., end='', flush=True)कि यह कहाँ अनुचित है? ओटीओएच, जब कई कार्यक्रम समान आउटपुट के लिए लिखते हैं, तो ट्रेड-मिक्स आउटपुट मिक्सअप को कम करने के लिए तत्काल प्रगति को देखकर शिफ्ट हो जाता है, और लाइन बफरिंग आकर्षक हो जाती है। तो शायद यह है बेहतर करने के लिए नहीं स्पष्ट लिखनाflush और नियंत्रण बाह्य बफरिंग?
बेनी चेर्नियाव्स्की-पास्किन

मेरे ख़्याल से नहीं। प्रक्रिया खुद तय करनी चाहिए कि वह कब और क्यों फोन करती है flush। बाहरी बफ़रिंग नियंत्रण यहाँ पर मजबूर है
डियोमास

7

पायथन 3 में, आप प्रिंट फंक्शन को बंदर-पैच कर सकते हैं, हमेशा फ्लश = ट्रू भेजने के लिए:

_orig_print = print

def print(*args, **kwargs):
    _orig_print(*args, flush=True, **kwargs)

जैसा कि एक टिप्पणी में बताया गया है, आप फ्लश पैरामीटर को एक मान पर बाँधकर इसे सरल बना सकते हैं functools.partial:

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

3
बस सोच रहा था, लेकिन यह एक सही उपयोग के लिए मामला नहीं होगा functools.partial?
0xC0000022L

धन्यवाद @ 0xC0000022L, यह बेहतर दिखता है! print = functools.partial(print, flush=True)मेरे लिए ठीक काम करता है।
12

@ 0xC0000022L वास्तव में, मैंने उस विकल्प को दिखाने के लिए पोस्ट को अपडेट किया है, इस ओर इशारा करने के लिए धन्यवाद
ओलिवर

3
यदि आप चाहते हैं कि हर जगह आवेदन करें,import builtins; builtins.print = partial(print, flush=True)
पर्किन्स

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
वहाँ एक विंडोज़ समतुल्य है: stackoverflow.com/questions/881696/…
टोबू

12
O_SYNC के पास उपयोगकर्ता-स्तरीय बफरिंग के साथ कुछ भी करने के लिए कुछ भी नहीं है जो इस प्रश्न के बारे में पूछ रहा है।
अप्पनवर्र

4

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

def write_flush(args, w=stdout.write):
    w(args)
    stdout.flush()

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

stdout.write = write_flush

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


3

आप एक अप्रतिबंधित फ़ाइल बना सकते हैं और इस फ़ाइल को sys.stdout पर असाइन कर सकते हैं।

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

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


3

वेरिएंट जो दुर्घटनाग्रस्त हुए बिना काम करता है (कम से कम win32 पर; अजगर 2.7, ipython 0.12) तो बाद में (कई बार) कहा जाता है:

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)

क्या आप सुनिश्चित हैं कि यह बफर नहीं है?
क्वांटम

1
क्या आपको sys.stdout is sys.__stdout__नाम विशेषता वाले प्रतिस्थापन ऑब्जेक्ट पर निर्भर होने के बजाय जांच करनी चाहिए ?
लेविज़

यह बढ़िया काम करता है अगर किसी कारण से gunicorn PYTHONUNBUFFERED का सम्मान नहीं कर रहा है।
ब्रायन अर्सुगा

3

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

  1. जैसा कि मैंने देखा, CPython (कम से कम लिनक्स पर) अलग-अलग तरीके से व्यवहार करता है, जहां आउटपुट जाता है। यदि यह टटी पर जाता है, तो आउटपुट प्रत्येक के बाद फ्लश हो \n'
    जाता है ' यदि यह एक पाइप / प्रक्रिया में जाता है, तो यह बफर हो जाता है और आप ऊपर सुझाए गए flush()समाधान या -u विकल्प का उपयोग कर सकते हैं ।

  2. आउटपुट बफ़रिंग से थोड़ा संबंधित:
    यदि आप इनपुट में लाइनों पर पुनरावृति करते हैं

    for line in sys.stdin:
    ...

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

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


यहाँ आपकी टिप्पणी है । यह पुराने पायथन संस्करणों पर एक बग हो सकता है। क्या आप उदाहरण कोड प्रदान कर सकते हैं? की तरह कुछ for line in sys.stdinबनामfor line in iter(sys.stdin.readline, "")
JFS

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

यह पढ़ने-आगे बग की तरह लग रहा है । यह केवल पायथन 2 पर होना चाहिए और यदि स्टड एक पाइप है। मेरी पिछली टिप्पणी का कोड इस मुद्दे को प्रदर्शित for line in sys.stdinकरता है ( विलंबित प्रतिक्रिया प्रदान करता है)
jfs

2

अप्रतिष्ठित आउटपुट प्राप्त करने का एक तरीका sys.stderrइसके बजाय उपयोग करना होगा sys.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
यह तब बहुत भ्रामक हो सकता है जब आप बाद में मानक पुनर्निर्देशन का उपयोग करके आउटपुट पर कब्जा करने की कोशिश करते हैं, और पाते हैं कि आप कुछ भी नहीं कैप्चर कर रहे हैं! ps आपका स्टडआउट बोल्ड और स्टफ किया जा रहा है।
फ़्रीस्पीस

1
Stderr के लिए चुनिंदा मुद्रण के बारे में एक बड़ी सावधानी यह है कि यह लाइनों को जगह से बाहर निकलने का कारण बनता है, इसलिए जब तक आपके पास टाइमस्टैम्प नहीं होता है तब तक यह बहुत भ्रमित हो सकता है।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.