Zwiększ rozmiar bufora standardowego Pythona

Nov 26 2020

Czy istnieje sposób, aby zwiększyć stdoutrozmiar bufora z 8182 w Pythonie lub opóźnić opróżnianie, dopóki nie zadzwonię flush?

Rzeczy, które wypróbowałem, ale nie działają:

  • Mogę obejść ten problem w systemie Windows, ponieważ mam bezpośredni dostęp do bufora (np. Zobacz moją odpowiedź na ten post ). Ale to nie działa dla Uniksa.
  • Mogę zwiększyć rozmiar bufora dla pliku, przekazując buffergo do konstruktora, jednak stdoutjest on już skonstruowany.
  • Wyłączenie buforowania ( python -u) oczywiście pogarsza sytuację!
  • Korzystanie z bufora tymczasowego napotyka te same problemy - stdoutjest opróżniane po skopiowaniu każdego 8192 bajtu z bufora tymczasowego.

Uzasadnienie: Celem jest zmniejszenie migotania konsoli. Buforowanie wszystkiego, zgodnie z tym pytaniem, rzeczywiście działa, na przykład gdy próbuję w C lub używając Windows API w Pythonie, ale limit 8182 w Pythonie wydaje się powodować problemy, których nie mogę obejść na Unixie.

Odpowiedzi

1 blhsing Nov 27 2020 at 05:29

Możesz opakować surowy strumień wyjściowy, dostępny jako sys.stdout.buffer, z większym rozmiarem buforu io.BufferedWriter, a następnie zawinąć wynikowy buforowany strumień binarny jako buforowany strumień tekstowy io.TextIOWrapper:

import io
import sys

sys.stdout = io.TextIOWrapper(io.BufferedWriter(sys.stdout.buffer, new_size))

Oto demonstracja efektu zwiększenia rozmiaru bufora wyjścia standardowego do 100000, aby nie opróżniał dwóch wydruków o długości 10000 znaków, dopóki nie zostanie wywołane ręczne opróżnianie:

import io
import sys
import time

print('Original buffer size:', io.DEFAULT_BUFFER_SIZE)
for large_buffer in False, True:
    if large_buffer:
        print('Increasing buffer size...')
        sys.stdout = io.TextIOWrapper(io.BufferedWriter(sys.stdout.buffer, 100000))
    for i in range(2):
        time.sleep(2)
        print(str(i * 2) * 10000)
        time.sleep(2)
        print(str(i * 2 + 1) *10000)
        print(f'Flush #{i + 1}')
        sys.stdout.flush()

Próbny: https://repl.it/@blhsing/UnkemptGullibleDecompiler

1 cz Nov 27 2020 at 16:39

Znalazłem odpowiedź, właściwie bardzo prostą:

my_stdout = open( 1, "w", buffering = 100000 )
  • 1jest filenodla stdout.
  • sys.stdout = my_stdoutmożna użyć do zmiany domyślnego printcelu.
  • Testowałem to tylko na Uniksie.