Prestazioni di loop vs espansione


9

Hai bisogno di suggerimenti di esperti sul confronto di seguito:

Segmento di codice tramite loop:

for file in `cat large_file_list`
do
    gzip -d $file
done

Segmento di codice mediante semplice espansione:

gzip -d `cat large_file_list`

Quale sarà più veloce? Devono manipolare un set di dati di grandi dimensioni.


1
La risposta corretta dipenderà dal tempo necessario per l'avvio gzipsul sistema, dal numero di file nell'elenco dei file e dalle dimensioni di tali file.
Kusalananda

L'elenco dei file avrà circa 1000 - 10000 file. Le dimensioni variano da alcuni kilobyte a 500 MB. Non ho idea di quanto tempo impiega gzip nel mio sistema. in qualche modo controllare?
Leon,

1
Ok, allora potrebbe anche dipendere dalla lunghezza dei nomi dei file . Se i nomi dei file sono lunghi, alcuni sistemi potrebbero generare un errore "Elenco argomenti troppo lungo" se si tentasse di farlo senza un ciclo poiché la sostituzione dei comandi comporterebbe una riga comandi troppo lunga per l'esecuzione della shell. Se non si desidera dipendere dal numero di file nell'elenco, utilizzare solo un ciclo. Stai trascorrendo molto tempo a decomprimere questi file rispetto alle altre elaborazioni che eseguirai su di essi?
Kusalananda

Leon dà un'occhiata ai risultati del mio test: "huge-arglist" è 20 volte più veloce di "loop" nelle mie impostazioni.

per un mezzo felice tra l'avvio del processo e la lunghezza della riga di comando, utilizzare qualcosa di simile xargs gzip -d < large_file_listma fare attenzione agli spazi nei nomi dei file, magari contr \\n \\0 large_file_list | xargs -0 gzip -d
w00t

Risposte:


19

complicazioni

Quanto segue funzionerà solo a volte:

gzip -d `cat large_file_list`

Tre problemi sono (nella bashe nella maggior parte delle altre shell tipo Bourne):

  1. Non funzionerà se un nome di file contiene una scheda spazio o caratteri di nuova riga (supponendo che $IFSnon sia stato modificato). Ciò è dovuto alla divisione della parola della shell .

  2. Può anche fallire se un nome file contiene caratteri glob-active. Questo perché la shell applicherà l' espansione del nome percorso all'elenco dei file.

  3. Fallirà anche se i nomi dei file iniziano con -(se POSIXLY_CORRECT=1questo vale solo per il primo file) o se esiste un nome qualsiasi -.

  4. Non funzionerà anche se ci sono troppi nomi di file per adattarsi a una riga di comando.

Il codice seguente è soggetto agli stessi problemi del codice sopra (tranne il quarto)

for file in `cat large_file_list`
do
    gzip -d $file
done

Soluzione affidabile

Se hai large_file_listesattamente un nome file per riga e un file chiamato -non è tra questi, e sei su un sistema GNU, allora usa:

xargs -rd'\n' gzip -d -- <large_file_list

-d'\n'indica xargsdi trattare ogni riga di input come un nome file separato.

-rdice di xargsnon eseguire il comando se il file di input è vuoto.

--dice gzipche i seguenti argomenti non devono essere trattati come opzioni anche se iniziano con -. -da solo verrebbe comunque trattato -invece del file chiamato -però.

xargsinserirà molti nomi di file su ciascuna riga di comando ma non così tanti da superare il limite della riga di comando. Ciò riduce il numero di volte in cui un gzipprocesso deve essere avviato e quindi lo rende veloce. È anche sicuro: i nomi dei file saranno anche protetti dalla suddivisione delle parole e dall'espansione del percorso .


Grazie per la risposta dettagliata. Capisco i tuoi 3 problemi citati. Il nome del file è semplice e non affronterà queste sfide poiché l'elenco può contenere fino a 20000. E la mia domanda è fondamentalmente sulle prestazioni di questi due segmenti. Grazie.
Leon,

1
@Leon Il forciclo sarà - di gran lunga - il più lento. Gli altri due metodi saranno molto vicini tra loro in velocità.
Giovanni 1024,

7
Inoltre, non eliminare i potenziali problemi: molte molte domande qui su StackExchange sono perché la divisione delle parole o l' espansione del percorso sono avvenute a persone che non se lo aspettavano.
Giovanni 1024

5
Nota anche che c'è una variazione nella lettura di un file con xargs: almeno la versione GNU ha --arg-fileun'opzione (forma breve -a). Quindi si potrebbe fare xargs -a large_file_list -rd'\n' gzip -d invece. In effetti, non vi è alcuna differenza, a parte il fatto che <è un operatore di shell e farebbe xargsleggere da stdin (che la shell "collega" al file), mentre -arenderebbe xargsesplicitamente aperto il file in questione
Sergiy Kolodyazhnyy

2
Terdon ha notato in un altro commento sull'uso paralleldi eseguire più copie di gzip, ma xargs(almeno quella GNU), ha anche il -Ppassaggio per quello. Su macchine multicore che potrebbero fare la differenza. Ma è anche possibile che la decompressione sia comunque completamente legata agli I / O.
ilkkachu,

12

Dubito che importerebbe molto.

Vorrei usare un ciclo, solo perché non so quanti file sono elencati nel file elenco e non (in genere) so se qualcuno dei nomi di file ha spazi nei loro nomi. La sostituzione di un comando che genererebbe un elenco di argomenti molto lungo può causare un errore "Elenco argomenti troppo lungo" quando la lunghezza dell'elenco generato è troppo lunga.

Il mio ciclo sarebbe simile

while IFS= read -r name; do
    gunzip "$name"
done <file.list

Ciò mi consentirebbe inoltre di inserire comandi per l'elaborazione dei dati dopo il gunzipcomando. In effetti, a seconda di cosa siano effettivamente i dati e cosa debba essere fatto con essi, potrebbe anche essere possibile elaborarli senza salvarli su file:

while IFS= read -r name; do
    zcat "$name" | process_data
done <file.list

(dov'è process_datauna pipeline che legge i dati non compressi dall'input standard)

Se l'elaborazione dei dati richiede più tempo rispetto alla loro decompressione, la questione se un ciclo sia più efficiente o meno diventa irrilevante.

Idealmente , preferirei non lavorare su un elenco di nomi di file, e invece utilizzare un modello globbing di nome file, come in

for name in ./*.gz; do
    # processing of "$name" here
done

dove ./*.gzè un modello che corrisponde ai file pertinenti. In questo modo non dipendiamo dal numero di file né dai caratteri utilizzati nei nomi dei file (possono contenere righe o altri caratteri spazi bianchi o iniziare con trattini, ecc.)

Relazionato:


5

Di questi due, quello con tutti i file passati a una singola chiamata gzipè probabilmente più veloce, proprio perché è necessario avviarlo solo gzipuna volta. (Cioè, se il comando funziona affatto, vedi le altre risposte per le avvertenze.)

Ma vorrei ricordare la regola d'oro dell'ottimizzazione : non farlo prematuramente.

  1. Non ottimizzare questo genere di cose prima di sapere che è un problema.

    Questa parte del programma richiede molto tempo? Bene, decomprimere file di grandi dimensioni potrebbe essere, e dovrai farlo comunque, quindi potrebbe non essere così facile rispondere.

  2. Misurare. Davvero, è il modo migliore per essere sicuri.

    Vedrai i risultati con i tuoi occhi (o con il tuo cronometro) e si applicheranno alla tua situazione che potrebbero non avere risposte casuali su Internet. Inserisci entrambe le varianti negli script ed esegui time script1.sh, e time script2.sh. (Fallo con un elenco di file compressi vuoti per misurare la quantità assoluta dell'overhead.)


0

Quanto è veloce il tuo disco?

Questo dovrebbe usare tutte le tue CPU:

parallel -X gzip -d :::: large_file_list

Quindi il tuo limite sarà probabilmente la velocità del tuo disco.

Puoi provare ad adattarti con -j:

parallel -j50% -X gzip -d :::: large_file_list

Questo eseguirà metà dei lavori in parallelo come il comando precedente e stresserà il disco di meno, quindi a seconda del disco questo può essere più veloce.

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.