Mengapa file echo> menggunakan lebih banyak waktu nyata daripada echo | sed> file?

28

Contoh di bawah ini mengejutkan saya. Tampaknya kontra intuitif ... selain dari fakta bahwa ada kumis lebih banyak waktu pengguna untuk echo | sedkombo.

Mengapa echomenggunakan begitu banyak waktu sistem ketika berjalan sendiri, atau seharusnya pertanyaannya adalah, Bagaimana sedmengubah keadaan permainan? Tampaknya echoperlu melakukan gema yang sama dalam kedua kasus ...

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
Peter.O
sumber
1
Reaksi usus saya ada hubungannya dengan buffering.
bahamat
1
@ Bahaham saya pikir Anda benar. Gema melakukan tulis terpisah () untuk setiap argumen. Sed mendukung mereka. Jadi versi pertama memiliki sejuta penulisan ke file biasa, melalui driver filesystem ke dalam lapisan perangkat blok, dan versi kedua memiliki sejuta penulisan yang masuk ke dalam pipa dan menulis lebih sedikit melalui lapisan kode kernel yang lebih mahal.
Alan Curry
@ Bahaham pasti buffering. time echo ... |cat >filedan bahkan waktu time echo ... |perl -ne 'print'yang mirip dengan sedversi.
StarNamer
4
Terima kasih kepada semua orang untuk penjelasan yang baik ... Jadi untuk penulisan multi-baris besar (dalam bash), kucing telah mendapatkan Penggunaan poin Kucing yang Bermanfaat :)
Peter.O

Jawaban:

29

bahamat dan Alan Curry melakukannya dengan benar: ini karena cara shell Anda buffer output echo. Secara khusus, shell Anda adalah bash, dan ia mengeluarkan satu writepanggilan sistem per baris. Oleh karena itu potongan pertama membuat 10.00000 menulis ke file disk, sedangkan potongan kedua membuat 10.00000 menulis ke pipa dan sed (sebagian besar secara paralel, jika Anda memiliki beberapa CPU) membuat jumlah penulisan ke file disk jauh lebih kecil karena outputnya buffering.

Anda dapat mengamati apa yang terjadi dengan menjalankan 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) ---

Kerang lain seperti ksh buffer output echobahkan ketika itu multiline, sehingga Anda tidak akan melihat banyak perbedaan.

$ 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

Dengan bash saya mendapatkan rasio waktu yang sama. Dengan ksh saya melihat potongan kedua berjalan lebih lambat.

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
Gilles 'SANGAT berhenti menjadi jahat'
sumber
Terima kasih ... kshContoh terakhir itu lebih sesuai dengan apa yang saya harapkan ...
Peter.O