Perché echo> file utilizza più tempo reale di echo | sed> file?


28

L'esempio, di seguito, mi ha sorpreso. Sembra essere contro intuitivo ... a parte il fatto che c'è un baffo di tempo in più per l' utente della echo | sedcombo.

Perché sta echousando così tanto tempo di sistema quando funziona da solo, o dovrebbe essere la domanda, come sedcambia lo stato di avanzamento? Sembra che echodovrebbe fare la stessa eco in entrambi i casi ...

time echo -n a\ {1..1000000}\ c$'\n' >file

# real    0m9.481s
# user    0m5.304s
# sys     0m4.172s

time echo -n a\ {1..1000000}\ c$'\n' |sed s/^\ // >file

# real    0m5.955s
# user    0m5.488s
# sys     0m1.580s

1
La mia reazione istintiva è che ha a che fare con il buffering.
bahamat,

1
@bahamat Penso che tu abbia ragione. L'eco fa un write () separato per ogni argomento. La sed li respinge. Quindi la prima versione ha un milione di scritture su un file normale, passando attraverso un driver del filesystem nel layer del dispositivo a blocchi, e la seconda versione ha un milione di scritture che vanno in una pipe e un po 'meno scritture che attraversano i layer più costosi del codice del kernel.
Alan Curry,

@bahamat Sicuramente buffering. time echo ... |cat >filee persino time echo ... |perl -ne 'print'sono tempi simili alla sedversione.
StarNamer,

4
Grazie a tutti per le buone spiegazioni ... Quindi per le grandi scritture multilinea (in bash), cat ha guadagnato un utile uso del punto Cat :)
Peter.O

Risposte:


29

bahamat e Alan Curry hanno ragione: questo è dovuto al modo in cui la shell esegue il buffering dell'output echo. In particolare, la tua shell è bash ed emette una writechiamata di sistema per linea. Quindi il primo snippet esegue 1000000 scritture su un file su disco, mentre il secondo snippet esegue 1000000 scritture su una pipe e sed (in gran parte in parallelo, se si hanno più CPU) effettua un numero considerevolmente più piccolo di scritture su un file su disco a causa del suo output buffering.

Puoi osservare cosa sta succedendo eseguendo strace .

$ strace -f -e write bash -c 'echo -n a\ {1..2}\ c$'\'\\n\'' >file'
write(1, "a 1 c\n", 6)                  = 6
write(1, " a 2 c\n", 7)                 = 7
$ strace -f -e write bash -c 'echo -n a\ {1..2}\ c$'\'\\n\'' | sed "s/^ //" >file'
Process 28052 attached
Process 28053 attached
Process 28051 suspended
[pid 28052] write(1, "a 1 c\n", 6)      = 6
[pid 28052] write(1, " a 2 c\n", 7)     = 7
Process 28051 resumed
Process 28052 detached
Process 28051 suspended
[pid 28053] write(1, "a 1 c\na 2 c\n", 12) = 12
Process 28051 resumed
Process 28053 detached
--- SIGCHLD (Child exited) @ 0 (0) ---

Altre shell come ksh bufferizzano l'output echoanche quando è multilinea, quindi non vedrai molta differenza.

$ strace -f -e write ksh -c 'echo -n a\ {1..2}\ c$'\'\\n\'' >file'
write(1, "a 1 c\n a 2 c\n", 13)         = 13
$ strace -f -e write ksh -c 'echo -n a\ {1..2}\ c$'\'\\n\'' | sed "s/^ //" >file'
Process 28058 attached
[pid 28058] write(1, "a 1 c\n a 2 c\n", 13) = 13
Process 28058 detached
--- SIGCHLD (Child exited) @ 0 (0) ---
write(1, "a 1 c\na 2 c\n", 12)          = 12

Con bash ottengo rapporti di temporizzazione simili. Con ksh vedo che il secondo frammento funziona più lentamente.

ksh$ time echo -n a\ {1..1000000}\ c$'\n' >file

real    0m1.44s
user    0m1.28s
sys     0m0.06s
ksh$ time echo -n a\ {1..1000000}\ c$'\n' | sed "s/^ //" >file

real    0m2.38s
user    0m1.52s
sys     0m0.14s

Grazie ... ksh
Quell'ultimo
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.