Cara menggunakan GNU paralel secara efektif

8

Misalkan saya ingin menemukan semua kecocokan dalam file teks terkompresi:

$ gzcat file.txt.gz | pv --rate -i 5 | grep some-pattern

pv --ratedigunakan di sini untuk mengukur throughput pipa. Di komputer saya ini sekitar 420Mb / s (setelah dekompresi).

Sekarang saya mencoba untuk melakukan grep paralel menggunakan GNU parallel.

$ gzcat documents.json.gz | pv --rate -i 5 | parallel --pipe -j4 --round-robin grep some-pattern

Sekarang throughput turun menjadi ~ 260Mb / s. Dan apa yang lebih menarik adalah parallelproses itu sendiri menggunakan banyak CPU. Lebih dari grepproses (tetapi kurang dari gzcat).

EDIT 1 : Saya sudah mencoba berbagai ukuran blok ( --block), serta nilai -N/ -Lopsi yang berbeda. Tidak ada yang membantu saya pada saat ini.

Apa yang saya lakukan salah?

Denis Bazhenov
sumber

Jawaban:

9

Saya sangat terkejut Anda mendapatkan 270 MB / s menggunakan GNU Parallel's --pipe. Tes saya biasanya maksimal sekitar 100 MB / s.

Kemacetan Anda kemungkinan besar terjadi di GNU Parallel: --pipetidak terlalu efisien. --pipepartNamun, adalah: Di sini saya bisa mendapatkan dalam urutan 1 GB / s per inti CPU.

Sayangnya ada beberapa batasan dalam menggunakan --pipepart:

  • File harus dapat dicari (yaitu tidak ada pipa)
  • Anda harus dapat menemukan awal catatan dengan --recstart / - recend (yaitu tidak ada file terkompresi)
  • Nomor baris tidak diketahui (sehingga Anda tidak dapat memiliki catatan 4-baris).

Contoh:

parallel --pipepart -a bigfile --block 100M grep somepattern
Ole Tange
sumber
1
Terima kasih. Adakah alasan mengapa --pipetidak efisien? Maksud saya apakah itu semacam masalah mendasar atau lebih spesifik implementasi.
Denis Bazhenov
2
Ya: GNU Parallel ditulis dalam perl, dan dengan --pipesetiap byte tunggal harus melalui proses tunggal, yang harus melakukan sedikit pemrosesan pada setiap byte. Dengan --pipepartsebagian besar byte tidak pernah dilihat oleh proses pusat: Mereka diproses oleh pekerjaan yang muncul. Karena cukup banyak baris yang menjadi hambatan dalam --pipesaya akan menyambut C / C ++ coder yang akan menulis ulang bagian yang kemudian akan dijalankan untuk orang-orang yang memiliki C-compiler di jalur mereka.
Ole Tange
2

grep sangat efektif - tidak ada gunanya menjalankannya secara paralel. Dalam perintah Anda hanya dekompresi yang membutuhkan lebih banyak cpu, tetapi ini tidak dapat diparalelkan.

Membagi input secara paralel membutuhkan lebih banyak CPU daripada mendapatkan garis yang cocok dengan grep.

Situasi berubah jika Anda ingin menggunakan bukannya grep sesuatu yang membutuhkan CPU lebih banyak untuk setiap baris - maka paralel akan lebih masuk akal.

Jika Anda ingin mempercepat operasi ini - lihat di mana bottleneck - mungkin itu dekompresi (kemudian bantu gunakan alat dekompresi lain atau cpu yang lebih baik) atau - baca dari disk (kemudian bantu gunakan alat dekompresi lain atau sistem disk yang lebih baik).

Dari pengalaman saya - terkadang lebih baik menggunakan lzma (-2 misalnya) untuk mengompres / mendekompresi file - ini memiliki kompresi yang lebih tinggi daripada gzip sehingga lebih sedikit data yang perlu dibaca dari disk dan kecepatannya sebanding.

undefine
sumber
1
Memang, ini kasus saya. Proses Java Java sangat lapar CPU digunakan bukan grep. Saya sedikit menyederhanakan pertanyaan. Dan tetap saja, makan paralel banyak CPU tidak memberikan banyak pekerjaan untuk proses Java.
Denis Bazhenov
1

Dekompresi adalah hambatan di sini. Jika dekompresi tidak diparalelkan secara internal, Anda tidak akan mencapainya sendiri. Jika Anda memiliki lebih dari satu pekerjaan seperti itu, maka tentu saja meluncurkannya secara paralel, tetapi saluran pipa Anda sendiri sulit untuk diparalelkan. Memisahkan satu aliran ke aliran paralel hampir tidak pernah sepadan, dan bisa sangat menyakitkan dengan sinkronisasi dan penggabungan. Terkadang Anda hanya harus menerima bahwa banyak core tidak akan membantu setiap tugas yang sedang Anda jalankan.

Secara umum, paralelisasi di shell sebagian besar harus pada tingkat proses independen.

orion
sumber
1
Sepertinya dekompresi tidak menjadi hambatan jika digunakan parallel. Saya setuju bahwa itu pasti dalam kasus pertama (tanpa paralel), tetapi dalam yang kedua (dengan paralel) hambatan ada di sisi paralel. Ini mengikuti dari pengamatan bahwa throughput turun secara signifikan yang diukur dengan pv. Jika bottleneck dalam dekompresi, throughput tidak akan mengubah apa pun yang Anda tambahkan ke pipeline. Ini definisi intuisi dari throughput, saya kira - hal yang paling membatasi throughput.
Denis Bazhenov
1
Ada kemungkinan bahwa grep sangat cepat, sehingga selesai lebih cepat daripada yang paralleldapat ditulis ke pipanya. Dalam hal ini, sebagian besar grepproses hanya menunggu untuk mendapatkan lebih banyak, sementara parallelitu bekerja sepanjang waktu untuk melipatgandakan blok menjadi beberapa pipa (yang merupakan operasi IO tambahan dan bahkan dapat memblokir dekompresi jika buffer penuh). Apakah Anda juga mencoba bermain dengan --blockparameter? Secara default 1Mbegitu sampai satu grep mendapatkan 1Mdata, sisanya hampir pasti sudah selesai. Karena itu kita kembali ke fakta bahwa tidak masuk akal untuk memaralelkan ini.
orion
1
Yap, saya sudah mencoba opsi ini dengan ukuran blok besar dan kecil. Serta nilai yang berbeda untuk -N/ -Lopsi. Sepertinya opsi default sangat dekat dengan optimal lokal yang pernah saya alami :)
Denis Bazhenov
1
Cobalah mengatur waktu dengan dan tanpa pv(dengan time). Dengan cara ini Anda bisa melihat apakah pvitu sendiri memperlambatnya. Jika ya, maka parallelmenyalin data ke dalam pipa jelas merupakan tambahan biaya tambahan. Dan bagaimanapun, saya cukup yakin, grephampir real-time dalam hal ini, terutama jika polanya adalah string sederhana tanpa banyak mundur. Selain itu, parallelakan interleave dan mengacaukan grepoutput.
orion
1
Saya akan periksa kembali bahwa pvitu sendiri tidak menyebabkan masalah, terima kasih atas sarannya.
Denis Bazhenov