Jak często Python opróżnia się do pliku?

228
  1. Jak często Python opróżnia się do pliku?
  2. Jak często Python spływa na standardowe wyjście?

Nie jestem pewien (1).

Jeśli chodzi o (2), uważam, że Python spływa na standardowe wyjście po każdej nowej linii. Ale jeśli przeciążasz stdout, aby znaleźć się w pliku, czy jest on tak często opróżniany?

Tim McJilton
źródło

Odpowiedzi:

332

Do operacji na plikach Python używa domyślnego buforowania systemu operacyjnego, chyba że skonfigurujesz go inaczej. Możesz określić rozmiar bufora, niebuforowany lub buforowany wiersz.

Na przykład funkcja open przyjmuje argument wielkości bufora.

http://docs.python.org/library/functions.html#open

„Opcjonalny argument buforowania określa pożądany rozmiar bufora pliku:”

  • 0 oznacza niebuforowane,
  • 1 oznacza buforowany wiersz,
  • każda inna wartość dodatnia oznacza użycie bufora o (przybliżonej) tej wielkości.
  • Buforowanie ujemne oznacza użycie domyślnego systemu, który jest zwykle buforowany liniowo dla urządzeń tty i w pełni buforowany dla innych plików.
  • Jeśli zostanie pominięty, zostanie użyta wartość domyślna systemu.

kod:

bufsize = 0
f = open('file.txt', 'w', buffering=bufsize)
Corey Goldberg
źródło
23
+1 dla części „buforowanej linii”. Właśnie tego szukałem i działa jak urok.
wodza
2
Używając Python 3.4.3, kiedy to robię open('file.txt', 'w', 1), uzyskuję odpowiednie buforowanie linii. Ale jeśli zrobię coś większego (chciałem open('file.txt', 'w', 512)), buforuje pełny io.DEFAULT_BUFFER_SIZE8192. Czy to błąd Pythona, błąd Linuksa lub błąd ID10t?
Bruno Bronosky,
Czy można zmienić buforowanie już otwartych strumieni? Powiedzmy, że chcę stdoutbyć buforowany w linii niezależnie od tego, czy jest to konsola, czy przekierowany do pliku?
Michaił T.
1
@CharlieParker podczas wywoływania write()uchwytu pliku, dane wyjściowe są buforowane w pamięci i gromadzone aż do zapełnienia bufora ... w tym czasie bufor zostaje „opróżniony” (zawartość jest zapisywana z bufora do pliku). Możesz jawnie opróżnić bufor, wywołując flush()metodę na uchwycie pliku.
Corey Goldberg,
3
Zauważ, że niebuforowany (0) jest dostępny tylko w trybie binarnym, a buforowany wiersz (1) jest dostępny tylko w trybie tekstowym.
ZaydH,
172

flush()Metodą można również wymusić opróżnienie bufora do pliku programowo .

with open('out.log', 'w+') as f:
    f.write('output is ')
    # some work
    s = 'OK.'
    f.write(s)
    f.write('\n')
    f.flush()
    # some other work
    f.write('done\n')
    f.flush()

Uznałem, że jest to przydatne podczas dostosowywania pliku wyjściowego tail -f.

kortina
źródło
54
Z dokumentów:Note: flush() does not necessarily write the file’s data to disk. Use flush() followed by os.fsync() to ensure this behavior.
bobismijnnaam
1
@ bobismijnnaam następnym razem link do wspomnianych dokumentów. Jedyne odniesienie, które mogę znaleźć, pochodzi z github.com/jprzywoski/python-reference/blob/master/source/docs/… i nie wiem, kto to jest.
Bruno Bronosky
5
@Bruno Bronosky Dobra uwaga. Dokumenty: Note: flush() does not necessarily write the file’s data to disk. Use flush() followed by os.fsync() to ensure this behavior.
bobismijnnaam
jestem zdezorientowany, co to w flushingogóle oznacza. Dlaczego tego potrzebujemy? Po co to jest? dlaczego mam się tym przejmować?
Charlie Parker
@CharlieParker, kiedy piszesz, piszesz do kopii (części) pliku w pamięci RAM, która może nie być przez jakiś czas zapisywana na dysku. Poprawia wydajność, ale może oznaczać utratę danych, jeśli kopia nigdy nie zostanie zapisana (dysk usunięty, awaria systemu operacyjnego itp.). flush () mówi Pythonowi, aby natychmiast zapisał ten bufor z powrotem na dysk. (Następnie os.fsync () informuje system operacyjny, aby również to zrobił. Istnieje wiele warstw buforów ...)
Rena
13

Nie wiem, czy dotyczy to również Pythona, ale myślę, że zależy to od używanego systemu operacyjnego.

Na przykład w systemie Linux dane wyjściowe do terminala opróżniają bufor w nowej linii, podczas gdy dane wyjściowe do plików są opróżniane tylko wtedy, gdy bufor jest pełny (domyślnie). Wynika to z faktu, że bardziej wydajne jest opróżnianie bufora mniej razy, a użytkownik jest mniej prawdopodobne, aby zauważyć, że dane wyjściowe nie są opróżniane w nowej linii w pliku.

Możesz być w stanie automatycznie opróżnić wyjście, jeśli tego potrzebujesz.

EDYCJA: Myślę, że w ten sposób spłukałbyś się automatycznie w Pythonie (na podstawie stąd )

#0 means there is no buffer, so all output
#will be auto-flushed
fsock = open('out.log', 'w', 0)
sys.stdout = fsock
#do whatever
fsock.close()
KLee1
źródło
12

Możesz również sprawdzić domyślny rozmiar bufora, wywołując atrybut tylko do odczytu DEFAULT_BUFFER_SIZE z modułu io.

import io
print (io.DEFAULT_BUFFER_SIZE)
N Randhawa
źródło
1
Dzięki! Dobrze wiedzieć, że Python ustawia to jako definicję systemu operacyjnego ... ale to pomaga dowiedzieć się, co system definiuje wcześniej.
Cometsong
2

Oto inne podejście, aż do PO, aby wybrać, które preferuje.

Gdy dołączasz poniższy kod do __init__pliku .py przed jakimkolwiek innym kodem, wiadomości drukowane wraz z printwszelkimi błędami nie będą już rejestrowane w pliku Log.txt Abletona, ale w celu oddzielenia plików na dysku:

import sys

path = "/Users/#username#"

errorLog = open(path + "/stderr.txt", "w", 1)
errorLog.write("---Starting Error Log---\n")
sys.stderr = errorLog
stdoutLog = open(path + "/stdout.txt", "w", 1)
stdoutLog.write("---Starting Standard Out Log---\n")
sys.stdout = stdoutLog

(w przypadku komputerów Mac zmień #username#nazwę folderu użytkownika. W systemie Windows ścieżka do folderu użytkownika będzie miała inny format)

Po otwarciu plików w edytorze tekstu, który odświeża zawartość po zmianie pliku na dysku (przykład dla komputerów Mac: TextEdit nie robi tego, ale TextWrangler robi to), zobaczysz, że dzienniki są aktualizowane w czasie rzeczywistym.

Kredyty: ten kod został skopiowany głównie ze skryptów kontrolnych liveAPI Nathana Ramelli

Mattijs
źródło