আউটপুট বাফারিং অক্ষম করুন


532

পাইথনের ইন্টারপ্রেটারে কি আউটপুট বাফারিং ডিফল্টরূপে সক্ষম হয় sys.stdout?

উত্তরটি যদি ইতিবাচক হয় তবে এটি অক্ষম করার সমস্ত উপায় কী?

এখনও অবধি পরামর্শ:

  1. -uকমান্ড লাইন সুইচ ব্যবহার করুন
  2. মোড়ানো sys.stdoutএকটি বস্তু যে প্রতি লেখার পর flushes মধ্যে
  3. PYTHONUNBUFFEREDএনভির ভার সেট করুন
  4. sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)

মৃত্যুদন্ড কার্যকর করার সময় sys/ sys.stdoutপ্রোগ্রামে কোনও বৈশ্বিক পতাকা সেট করার অন্য কোনও উপায় আছে কি ?


7
পাইথন 3 এ `মুদ্রণের জন্য, এই উত্তরটি দেখুন
অ্যান্টি হাপাল

1
আমি মনে করি এর একটি অপূর্ণতা -uহ'ল এটি বাইকোড সংকলিত বা __main__.pyএন্ট্রি পয়েন্ট হিসাবে কোনও ফাইল সহ অ্যাপ্লিকেশনগুলির জন্য কাজ করবে না ।
akhan

উত্তর:


443

মেলিং লিস্টে ম্যাগনাস লিকার উত্তর থেকে :

আপনি "পাইথন-ইউ" (বা #! / Usr / bin / env পাইথন-ইউ ইত্যাদি) ব্যবহার করে বা পরিবেশ পরিবর্তনশীল পাইথোনুনবুফারড সেট করে পুরো অজগর প্রক্রিয়াটির জন্য বাফারিং এড়িয়ে যেতে পারেন।

আপনি সিস.স্টডআউটকে অন্য কোনও স্ট্রিমের সাথে রিপারের মতো প্রতিস্থাপন করতে পারেন যা প্রতিটি কল করার পরে ফ্লাশ করে।

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__। কেবল আপনার যদি এটির প্রয়োজন হয় =)
অ্যান্টি রাসিনেন

39
#!/usr/bin/env python -uকাজ করে না !! দেখতে এখানে
Wim

6
__getattr__শুধু উত্তরাধিকার এড়ানোর জন্য ?!
ভ্লাদিমির কালেশেভ

31
কিছু মাথাব্যথা বাঁচানোর জন্য কিছু নোট: যেমন আমি লক্ষ্য করেছি, আউটপুট টিটি বা অন্য কোনও প্রক্রিয়া / পাইপে যায় কিনা তার উপর নির্ভর করে আউটপুট বাফারিং আলাদাভাবে কাজ করে। যদি এটি কোনও টিটিতে যায়, তবে এটি প্রতিটি after n এর পরে ফ্লাশ করা হয় তবে একটি পাইপে এটি বাফার হয়। পরবর্তী ক্ষেত্রে আপনি এই ফ্লাশিং সমাধানগুলি ব্যবহার করতে পারেন। সিপিথনে (পাইপিতে নয় !!!): আপনি যদি সিস্টেস্টে লাইনের জন্য ইনপুটটি দিয়ে পুনরাবৃত্তি করেন : ... তবে লুপটির বডিটি চালানোর আগে লুপটি লুপটি বেশ কয়েকটি লাইন সংগ্রহ করবে। এটি বাফারিংয়ের মতো আচরণ করবে যদিও এটি ব্যাচিং নয়। পরিবর্তে, সত্য হিসাবে করুন: লাইন = sys.stdin.readline ()
tzp

5
@tzp: আপনি ব্যবহার করতে পারে iter()পরিবর্তে whileলুপ: for line in iter(pipe.readline, ''):। পাইথন 3 এ আপনার দরকার নেই যেখানে for line in pipe:যত তাড়াতাড়ি সম্ভব ফলন হয়।
jfs

122

আমি বরং আমার উত্তরটি কীভাবে মুদ্রণ ফাংশনের আউটপুট ফ্লাশ করব? বা পাইথনের মুদ্রণ ফাংশনটিতে যা বাফারকে ডাকা হলে ফ্লাশ করে? , তবে যেহেতু এগুলির একটির সদৃশ হিসাবে চিহ্নিত করা হয়েছে (যা আমি মানি না) আমি এখানে এটার উত্তর দেব।

পাইথন ৩.৩ থেকে মুদ্রণ () মূল শব্দটি "ফ্লাশ" সমর্থন করে ( ডকুমেন্টেশন দেখুন ):

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)

ক্রেডিট: "সেবাস্তিয়ান", পাইথন মেলিং তালিকার কোথাও।


পাইথন 3 এ আপনি মুদ্রণ ফাংশনের নামটি ফ্লাশিংয়ের সাহায্যে ওভাররাইড করতে পারেন। যদিও এটি একটি নোংরা কৌশল!
meawoppl

16
@ মাওওপ্পল: আপনি পাইথন ৩.৩ থেকে 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দেওয়া বাদে )।

দ্রষ্টব্য, (ক) যে এটি প্রশ্নের আংশিক উত্তর দেয় কারণ এটি সমস্ত আউটপুট পুনর্নির্দেশ করে না। তবে আমার ধারণা , পাইথনে / ইন printআউটপুট তৈরির সর্বাধিক সাধারণ উপায় , সুতরাং এই 2 টি লাইন সম্ভবত বেশিরভাগ ব্যবহারের ক্ষেত্রে আবৃত।stdoutstderr

দ্রষ্টব্য (খ) যে এটি কেবলমাত্র মডিউল / স্ক্রিপ্টে কাজ করে যেখানে আপনি এটি সংজ্ঞায়িত করেছেন। মডিউলটি লেখার সময় এটি ভাল হতে পারে কারণ এটির সাথে গণ্ডগোল হয় না sys.stdout

পাইথন 2flush আর্গুমেন্ট সরবরাহ করে না , তবে আপনি printএখানে https://stackoverflow.com/a/27991478/3734258 বর্ণিত হিসাবে পাইথন 3-প্রকারের ফাংশন অনুকরণ করতে পারেন ।


1
flushপাইথন 2 তে কোনও কোয়ার্গ নেই Ex
o11c

@ ও 11 সি, হ্যাঁ আপনি ঠিক বলেছেন। আমি নিশ্চিত আমি এটা পরীক্ষিত কিন্তু একরকম আমি আপাতদৃষ্টিতে বিভ্রান্ত হয়েছিল ( 'আমি আমার উত্তর পরিবর্তন, আশা করি এখন হয়েছে ধন্যবাদ।
টিম

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 (টেম্প_এফডি, ফাইলনো) এর আগে খোলে () )। আমি যখন থ্রেডস্যানিটাইজারের অধীনে আপনার কৌশলটি ব্যবহার করার চেষ্টা করেছি তখন এটি আমি খুঁজে পেলাম যা ঠিক এটি করে। ব্যর্থতাটি আরও জোরে জোরে তৈরি করা হয় যে ডুপ 2 () EBUSY এর সাথে ব্যর্থ হয় যখন এটি খোলা () এর সাথে দৌড় দেয়; দেখতে stackoverflow.com/questions/23440216/...
ডন ডিম পাড়া

13

পাইথন ২.6, ২.7, এবং ৩.২ এ নিম্নলিখিত কাজ করে:

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)

এটি দু'বার চালান এবং এটি উইন্ডোগুলিতে ক্র্যাশ হয়ে যায় :-)
মাইকেল ক্লারেক্স

@ মিশেলক্লারেক্স এমএমএম হুম, সর্বদা আপনার ফাইলগুলি এক্সডি বন্ধ করতে ভুলবেন না।

OSError: [Errno 29] Illegal seeksys.stdout = os.fdopen(sys.stdout.fileno(), 'a+', buf_arg)
রাস্পবিয়ান

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)আমার জন্য ভাল কাজ করে।
মারসফট

@ 0xC0000022L সত্যিই, আমি সেই বিকল্পটি দেখানোর জন্য পোস্টটি আপডেট করেছি, তা উল্লেখ করার জন্য ধন্যবাদ
অলিভার

2
আপনি যদি এটি সর্বত্র প্রয়োগ করতে চান,import builtins; builtins.print = partial(print, flush=True)
পার্কিনস

4

ফ্লাই-এ ফ্লাইগুলি পরিবর্তন করতে আপনি এফসিএনটিএলও ব্যবহার করতে পারেন।

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
উইন্ডোজ সমতুল্য: স্ট্যাকওভারফ্লো.com
টুবু

12
এই প্রশ্নটি সম্পর্কে জিজ্ঞাসা করা ব্যবহারকারী-স্থান-স্তরের বাফারিংয়ের সাথে ওএসওয়াইএনসির কিছুই করার নেই।
apenwarr

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

ভেরিয়েন্ট যা ক্রাশ ছাড়াই কাজ করে (কমপক্ষে উইন 32 এ; পাইথন ২.7, আইপথন ০.০২) তারপরে পরবর্তীকালে বলা হয় (একাধিক বার):

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__নামের বৈশিষ্ট্যযুক্ত প্রতিস্থাপনের উপর নির্ভর করার পরিবর্তে আপনার কি পরীক্ষা করা উচিত ?
লিউজ

যদি কোনও কারণে গ্যানিকর্ন পাইথুনবুফার্ডকে সম্মান না করে তবে এটি দুর্দান্ত কাজ করে।
ব্রায়ান আরসুগা

3

(আমি একটি মন্তব্য পোস্ট করেছি, তবে এটি কোনওভাবে হারিয়ে গেছে। সুতরাং, আবার :)

  1. যেমন আমি লক্ষ্য করেছি, সিপিথন (কমপক্ষে লিনাক্সে) আউটপুটটি কোথায় যায় তার উপর নির্ভর করে আলাদা আচরণ করে। যদি এটি কোনও টিটিতে যায়, তবে প্রতিটির পরে আউটপুট ফ্লাশ করা হয় ' \n'
    এটি যদি পাইপ / প্রক্রিয়াতে চলে যায় তবে এটি বাফার হয় এবং আপনি উপরের প্রস্তাবিত flush()ভিত্তিক সমাধানগুলি বা -u বিকল্পটি ব্যবহার করতে পারেন ।

  2. আউটপুট বাফারিংয়ের সাথে সামান্য সম্পর্কিত:
    আপনি যদি ইনপুটটিতে লাইনগুলি দিয়ে পুনরাবৃত্তি করেন

    for line in sys.stdin:
    ...

তারপর জন্য মধ্যে বাস্তবায়ন CPython কিছুদিনের জন্য ইনপুট সংগ্রহ করবে এবং তারপর ইনপুট লাইন একটি গুচ্ছ জন্য লুপ শরীরের চালানো। যদি আপনার স্ক্রিপ্ট প্রতিটি ইনপুট লাইনের জন্য আউটপুট লিখতে চলেছে flush(), তবে এটি আউটপুট বাফারিংয়ের মতো দেখাতে পারে তবে এটি আসলে ব্যাচিং therefore মজার বিষয় হল, পাইপিতে আপনার এই আচরণ নেই । এটি এড়াতে, আপনি ব্যবহার করতে পারেন

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


আপনার মন্তব্য এখানে । এটি পুরানো পাইথন সংস্করণগুলিতে একটি বাগ হতে পারে। আপনি উদাহরণ কোড প্রদান করতে পারেন? ভালো কিছু for line in sys.stdinবনামfor line in iter(sys.stdin.readline, "")
JFS

সিস্টেমে লাইনের জন্য: মুদ্রণ ("লাইন:" + লাইন); 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!"

স্টাডাউট পুনরায় সেট করতে আপনি কেবল এটি করতে পারেন:

sys.stdout = sys.__stdout__

1
আপনি পরে স্ট্যান্ডার্ড পুনঃনির্দেশ ব্যবহার করে আউটপুট ক্যাপচার করার চেষ্টা করবেন এবং আপনি কিছুই ক্যাপচার করছেন না এমনটি হতে পারে এটি খুব বিভ্রান্তিকর হতে পারে! PS আপনার স্টাডাউট সাহসী এবং স্টাফ করা হচ্ছে।
ফ্রিস্পেস

1
স্ট্যাডারকে নির্বাচন করে মুদ্রণের বিষয়ে একটি বড় সতর্কতা হ'ল এটি লাইনগুলি স্থানের বাইরে উপস্থিত হওয়ার কারণ হিসাবে আপনার কাছেও টাইমস্ট্যাম্প না থাকলে এটি খুব বিভ্রান্তি পেতে পারে।
haridsv
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.