Ogni quanto tempo Python scarica un file?


228
  1. Con quale frequenza Python scarica un file?
  2. Con quale frequenza Python scarica lo stdout?

Non sono sicuro di (1).

Per quanto riguarda (2), credo che Python arrossisca allo stdout dopo ogni nuova riga. Ma, se sovraccarichi stdout per essere su un file, si scarica spesso?

Risposte:


332

Per le operazioni sui file, Python utilizza il buffering predefinito del sistema operativo, a meno che non venga configurato diversamente. È possibile specificare una dimensione del buffer, senza buffer o con buffer di linea.

Ad esempio, la funzione aperta accetta un argomento relativo alla dimensione del buffer.

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

"L'argomento di buffering opzionale specifica la dimensione del buffer desiderata del file:"

  • 0 significa senza buffer,
  • 1 significa buffer di linea,
  • qualsiasi altro valore positivo significa utilizzare un buffer di (approssimativamente) tale dimensione.
  • Un buffering negativo significa utilizzare l'impostazione predefinita del sistema, che di solito è buffer di linea per i dispositivi tty e completamente buffer per altri file.
  • Se omesso, viene utilizzato il valore predefinito di sistema.

codice:

bufsize = 0
f = open('file.txt', 'w', buffering=bufsize)

23
+1 per la parte "buffer di riga". Questo è esattamente quello che stavo cercando e funziona come un fascino.
Rein

2
Utilizzando Python 3.4.3 quando lo faccio open('file.txt', 'w', 1)ottengo il buffering di linea corretto. Ma se faccio qualcosa di più grande (lo volevo open('file.txt', 'w', 512)), bufferizza l'intero io.DEFAULT_BUFFER_SIZE8192. È un bug di Python, un bug di Linux o un bug ID10t?
Bruno Bronosky,

È possibile modificare il buffering per i flussi già aperti ? Dì, voglio stdoutessere bufferizzato in linea indipendentemente dal fatto che si tratti di una console o reindirizzato a un file?
Mikhail T.,

1
@CharlieParker quando si chiama write()un handle di file, l'output viene bufferizzato in memoria e accumulato fino a quando il buffer non è pieno ... a quel punto il buffer viene "svuotato" (il contenuto viene scritto dal buffer nel file). È possibile svuotare esplicitamente il buffer chiamando il flush()metodo su un handle di file.
Corey Goldberg

3
Si noti che senza buffer (0) è disponibile solo in modalità binaria e il buffer di riga (1) è disponibile solo in modalità testo.
ZaydH

172

È anche possibile forzare lo svuotamento del buffer su un file a livello di codice con il flush()metodo.

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()

Ho trovato questo utile quando si esegue la coda di un file di output con tail -f.


54
Dai documenti: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 link la prossima volta a detti documenti. L'unico riferimento che posso trovare è da github.com/jprzywoski/python-reference/blob/master/source/docs/… e non so chi sia.
Bruno Bronosky,

5
@Bruno Bronosky Un buon punto. Documenti: Note: flush() does not necessarily write the file’s data to disk. Use flush() followed by os.fsync() to ensure this behavior.
bobismijnnaam,

ciò che sono confuso è flushinganche il significato del termine . Perchè ne abbiamo bisogno? Cosa serve? perché dovrei preoccuparmene?
Charlie Parker,

@CharlieParker quando scrivi, scrivi su una copia di (parte del) file nella RAM, che potrebbe non essere salvata sul disco per un po '. Migliora le prestazioni, ma può significare la perdita di dati se quella copia non viene mai scritta (disco rimosso, crash del sistema operativo, ecc.). flush () dice a Python di riscrivere immediatamente quel buffer sul disco. (Quindi, os.fsync () dice anche al SO di farlo. Ci sono molti livelli di buffer ...)
Rena

13

Non so se questo si applica anche a Python, ma penso che dipenda dal sistema operativo in uso.

Su Linux, ad esempio, l'output sul terminale scarica il buffer su una nuova riga, mentre per l'output su file si scarica solo quando il buffer è pieno (per impostazione predefinita). Questo perché è più efficiente svuotare il buffer meno volte e l'utente ha meno probabilità di notare se l'output non viene scaricato su una nuova riga in un file.

Potresti essere in grado di scaricare automaticamente l'output se è quello che ti serve.

EDIT: Penso che si scarica automaticamente in Python in questo modo (basato da qui )

#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()

12

È inoltre possibile verificare la dimensione del buffer predefinita chiamando l'attributo DEFAULT_BUFFER_SIZE di sola lettura dal modulo io.

import io
print (io.DEFAULT_BUFFER_SIZE)

1
Grazie! È bene sapere che Python lo imposta come definisce il sistema operativo ... ma questo aiuta a scoprire ciò che il sistema operativo pre-definisce.
Cometsong,

2

Ecco un altro approccio, fino all'OP per scegliere quale preferisce.

Quando si include il codice riportato di seguito nel __init__file .py prima di qualsiasi altro codice, i messaggi stampati con printe gli eventuali errori non verranno più registrati in Log.txt di Ableton ma per separare i file sul disco:

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

(per Mac, cambiare #username#il nome della cartella dell'utente. Su Windows il percorso della cartella dell'utente avrà un formato diverso)

Quando apri i file in un editor di testo che aggiorna il suo contenuto quando il file su disco viene modificato (esempio per Mac: TextEdit no, ma TextWrangler lo fa), vedrai i registri essere aggiornati in tempo reale.

Riconoscimenti: questo codice è stato copiato principalmente dagli script della superficie di controllo liveAPI di Nathan Ramella

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.