Bagaimana ksh93 begitu cepat?

9

Jadi, secara umum, saya cenderung mencari sedpengolahan teks - terutama untuk file besar - dan biasanya menghindari melakukan hal-hal di shell itu sendiri.

Saya pikir, itu mungkin berubah. Saya mencari-cari man kshdan memperhatikan ini:

<#pattern     Seeks forward to the beginning of the
              next line containing pattern.

<##pattern    The same as <# except that  the  por
              tion  of  the file that is skipped is
              copied to standard output.

Skeptis tentang kegunaan dunia nyata, saya memutuskan untuk mencobanya. Aku melakukannya:

seq -s'foo bar
' 1000000 >file

... untuk sejuta baris data yang terlihat seperti:

1foo bar
...
999999foo bar
1000000

... dan mengadu itu sedseperti:

p='^[^0-8]99999.*bar'
for c in "sed '/$p/q'" "ksh -c ':<##@(~(E)$p)'"    
do </tmp/file eval "time ( $c )"
done | wc -l

Jadi kedua perintah harus mendapatkan bar 999999foo dan implementasi pencocokan pola mereka harus mengevaluasi setidaknya awal dan akhir setiap baris untuk melakukannya. Mereka juga harus memverifikasi char pertama terhadap pola yang dinegasikan. Ini adalah hal yang sederhana, tapi ... Hasilnya tidak seperti yang saya harapkan:

( sed '/^[^0-8]99999.*bar/q' ) \
    0.40s user 0.01s system 99% cpu 0.419 total
( ksh -c ':<##@(~(E)^[^0-8]99999.*bar)' ) \
    0.02s user 0.01s system 91% cpu 0.033 total
1999997

kshmenggunakan ERE di sini dan sedBRE. Saya melakukan hal yang sama dengan kshdan pola shell sebelumnya tetapi hasilnya tidak berbeda.

Bagaimanapun, itu perbedaan yang cukup signifikan - kshmengungguli sed10 kali lipat. Saya telah membaca sebelumnya bahwa David Korn menulis io lib-nya sendiri dan mengimplementasikannya ksh- mungkin ini terkait? - tapi saya tidak tahu apa-apa tentang itu. Bagaimana cangkangnya melakukan ini dengan sangat baik?

Bahkan yang lebih menakjubkan bagi saya adalah kshbenar - benar meninggalkan offset tepat di tempat Anda memintanya. Untuk mendapatkan (hampir) sama dengan (GNU) sed Anda harus menggunakan -u- sangat lambat .

Inilah tes grepv ksh.:

1000000         #grep + head
( grep -qm1 '^[^0-8]99999.*bar'; head -n1; ) \
    0.02s user 0.00s system 90% cpu 0.026 total
999999foo bar   #ksh + head
( ksh -c ':<#@(~(E)^[^0-8]99999.*bar)'; head -n1; )  \
    0.02s user 0.00s system 73% cpu 0.023 total

kshberdetak di grepsini - tetapi tidak selalu - mereka cukup terikat. Namun, itu cukup bagus, dan ksh memberikan headmasukan lookahead - dimulai sebelum pertandingan.

Sepertinya terlalu bagus untuk menjadi kenyataan, kurasa. Apa yang dilakukan perintah-perintah ini secara berbeda di bawah tenda?

Oh, dan ternyata tidak ada subkulit di sini:

ksh -c 'printf %.5s "${<file;}"'
mikeserv
sumber
Apakah patternekspresi reguler atau pola shell yang lebih sederhana?
muru
@uru - Bisa jadi, tapi saya tidak pandai mengubah orang-orang di sekitar. Dalam contoh itu adalah pola shell - default.
mikeserv
@muru - Saya menambahkan satu dengan regex.
mikeserv

Jawaban:

8

Tidak hanya ksh menggunakan sfio tetapi juga menggunakan pengalokasi memori kustom sendiri.

Namun demikian, dugaan saya adalah sfio membuat perbedaan dalam kasus ini. Saya baru saja mencoba menjalankan contoh Anda di bawah strace dan dapat melihat bahwa panggilan ksh membaca / menulis ~ 200 kali (65 blok KB) sementara sed melakukannya ~ 3400 kali (blok 4 KB). Dengan sed -u laptop saya hampir meleleh, pembacaan dilakukan per byte dan menulis per baris. Ksh sederhana menggunakan lseek. Grep menggunakan baca ~ 400 kali (32 blok KB).

Miroslav Franc
sumber
Ya - tidak terbebani bukan untuk menjadi lemah hati. Saya ingin tahu apakah kshmesin regex seefisien io? Bagaimanapun, terima kasih banyak atas jawabannya. Saya minta maaf untuk laptop Anda. Bagaimana dengan pengalokasi memori khusus? Apakah Anda memiliki lebih dari itu?
mikeserv
1
Sayangnya tidak. Tentu saja Anda dapat mengunduh kode sumber dari & t situs web, tetapi hanya itu saja. Perpustakaan disebut AST dan berisi pengalokasi, mesin regex dan banyak hal lainnya. Jadi sangat mungkin bahwa kombinasi semua hal itu membuat ksh jauh lebih cepat.
Miroslav Franc
Terima kasih - ini juga tampak menjanjikan: Beberapa komponen yang tersedia dalam koleksi perangkat lunak AST adalah: Perintah POSIX Sebagian besar perintah POSIX standar tersedia dalam koleksi AST. Banyak yang dikodekan sebagai fungsi pustaka yang dapat ditambahkan ke ksh sebagai perintah bawaan yang secara dramatis meningkatkan kinerja. - Sekarang saya hanya harus mencari cara untuk membangunnya,
mikeserv
1
@mikeserv ksh dapat dibangun untuk menggunakan pengalokasi vmalloc Phong Vo . Artikel jurnal tersedia di tautan itu.
Mark Plotnick