Ketika grep
atau sed
digunakan dengan opsi --extended-regexp
dan pola {1,9999}
adalah bagian dari regexp yang digunakan, kinerja perintah ini menjadi rendah. Agar lebih jelas, di bawah ini diterapkan beberapa tes. [1] [2]
- Kinerja relatif dari
grep -E
,egrep
dansed -E
hampir sama, jadi hanya tes yang dibuat dengangrep -E
yang disediakan.
Tes 1
$ time grep -E '[0-9]{1,99}' < /dev/null
real 0m0.002s
Tes 2
$ time grep -E '[0-9]{1,9999}' < /dev/null
> real 0m0.494s
Tes 3
$ time grep -E '[0123456789] {1,9999}' </ dev / null > 21m43.947s nyata
Tes 4
$ time grep -E '[0123456789]+' < /dev/null
$ time grep -E '[0123456789]*' < /dev/null
$ time grep -E '[0123456789]{1,}' < /dev/null
$ time grep -P '[0123456789]{1,9999}' < /dev/null
real 0m0.002s
Apa alasan perbedaan kinerja yang signifikan ini?
command-line
grep
regex
pa4080
sumber
sumber
[0-9]+
juga)time grep -E '[0-9]{1,99}' </dev/null
vstime grep -E '[0-9]{1,9999}' </dev/null
. Bahkan tanpa input , perintah kedua lambat (pada 16.04). Seperti yang diharapkan, menghilangkan-E
dan melarikan diri{
dan}
berperilaku sama dan mengganti-E
dengan-P
tidak lambat (PCRE adalah mesin yang berbeda). Paling menarik adalah berapa banyak cepat[0-9]
adalah dari.
,x
, dan bahkan[0123456789]
. Dengan semua itu dan{1,9999}
,grep
mengkonsumsi sejumlah besar RAM; Saya belum berani membiarkannya berjalan lebih dari ~ 10 menit.{
}
ini'
'
dikutip ; shell melewati mereka tidak berubahgrep
. Bagaimanapun,{1,9999}
akan menjadi ekspansi penjepit yang sangat cepat dan sederhana . Shell hanya akan memperluas ke1 9999
.ps
dantop
memverifikasigrep
melewati argumen yang diharapkan dan itu, tidakbash
, mengkonsumsi banyak RAM dan CPU. Saya berharapgrep
dansed
keduanya menggunakan fungsi regex POSIX diimplementasikan dalam libc untuk pencocokan BRE / ERE; Saya seharusnya tidak benar-benar berbicara tentanggrep
desain secara khusus, kecuali sejauhgrep
pengembang memilih untuk menggunakan perpustakaan itu.time grep ... < /dev/null
, sehingga orang tidak mengacaukan masalah sebenarnya dengan data yang diumpankan kegrep
dan hal-hal asing lainnya.Jawaban:
Perhatikan bahwa bukan pencocokan yang membutuhkan waktu, tetapi pembangunan RE. Anda akan menemukan bahwa itu menggunakan cukup banyak RAM juga:
Jumlah allocs tampaknya kira-kira sebanding dengan jumlah iterasi, tetapi memori yang dialokasikan tampaknya tumbuh secara eksponensial.
Itu tergantung pada bagaimana GNU regexps diimplementasikan. Jika Anda mengkompilasi GNU
grep
denganCPPFLAGS=-DDEBUG ./configure && make
, dan menjalankan perintah-perintah itu, Anda akan melihat efek eksponensial dalam aksi. Pergi lebih dalam dari itu akan berarti melalui banyak teori tentang DFA dan terjun ke implementasi regn gnulib.Di sini, Anda dapat menggunakan PCRE sebagai gantinya yang tampaknya tidak memiliki masalah yang sama:
grep -Po '[0-9]{1,65535}'
(maksimum, meskipun Anda selalu dapat melakukan hal-hal seperti[0-9](?:[0-9]{0,10000}){100}
untuk 1 hingga 1.000 repetisi) tidak membutuhkan waktu atau memori lebih lama dari itugrep -Po '[0-9]{1,2}'
.sumber
grep -Po '[0-9]{1,9999}
yang tampaknya tidak memiliki masalah.sed -E
ataugrep -E
, tetapi diawk
juga memiliki kinerja yang rendah ini (sekitar perintah awk terakhir). mungkinawk
juga tidak bisa menggunakan PCRE?