Saya mencoba melakukan hitungan catatan pada file gzip 7,6 GB. Saya menemukan beberapa pendekatan menggunakan zcat
perintah.
$ zcat T.csv.gz | wc -l
423668947
Ini berfungsi tetapi butuh terlalu banyak waktu (lebih dari 10 menit untuk menghitungnya). Saya mencoba beberapa pendekatan seperti
$ sed -n '$=' T.csv.gz
28173811
$ perl -lne 'END { print $. }' < T.csv.gz
28173811
$ awk 'END {print NR}' T.csv.gz
28173811
Ketiga perintah ini menjalankan cukup cepat tetapi memberikan hitungan yang salah dari 28173811.
Bagaimana saya bisa melakukan penghitungan catatan dalam jumlah waktu minimal?
Jawaban:
Perintah
sed
,perl
danawk
yang Anda sebutkan mungkin benar, tetapi mereka semua membaca data yang dikompresi dan menghitung karakter baris baru di dalamnya. Karakter baris baru ini tidak ada hubungannya dengan karakter baris baru dalam data yang tidak terkompresi.Untuk menghitung jumlah baris dalam data yang tidak dikompresi, tidak ada jalan lain untuk mengompresnya. Pendekatan Anda dengan
zcat
adalah pendekatan yang benar dan karena datanya sangat besar, akan membutuhkan waktu untuk mengompresnya.Sebagian besar utilitas yang berhubungan dengan
gzip
kompresi dan dekompresi kemungkinan besar akan menggunakan rutinitas shared library yang sama untuk melakukannya. Satu-satunya cara untuk mempercepatnya adalah dengan menemukan implementasi darizlib
rutinitas yang entah bagaimana lebih cepat daripada yang default, dan membangun kembali miszcat
untuk menggunakannya.sumber
zcat
. Bagian penting dari pekerjaanzcat
menghasilkan keluaran aktual. Tetapi jika Anda hanya menghitung\n
karakter, itu tidak perlu.gzip
kompresi pada dasarnya bekerja dengan mengganti string panjang umum dengan string lebih pendek. Jadi, Anda hanya perlu peduli dengan string panjang dalam kamus yang berisi\n
, dan menghitung kemunculan (terbobot) dari mereka. Misalnya karena aturan bahasa Inggris,.\n
adalah string 16 bit yang umum.Gunakan unpigz.
Jawabannya Kusalananda adalah benar, Anda akan perlu untuk uncompress bahwa seluruh file untuk memindai isinya.
/bin/gunzip
melakukan ini secepat mungkin, pada satu inti. Pigz adalah implementasi paralelgzip
yang dapat menggunakan banyak core.Sayangnya, dekompresi itu sendiri dari file gzip normal tidak bisa diparalelkan, tapi
pigz
memang menawarkan versi perbaikan darigunzip
,unpigz
, yang melakukan pekerjaan terkait seperti membaca, menulis, dan menghitung checksum di thread terpisah. Dalam beberapa tolok ukur cepat,unpigz
hampir dua kali lebih cepatgunzip
dari pada mesin i5 inti saya.Instal
pigz
dengan pengelola paket favorit Anda, dan gunakanunpigz
sebagai gantigunzip
, atauunpigz -c
alih-alihzcat
. Jadi perintah Anda menjadi:Semua ini mengasumsikan bottleneck adalah CPU, bukan disk, tentu saja.
sumber
pigz
Halaman manual saya menyatakan bahwa Dekompresi tidak dapat diparalelkan, setidaknya tidak tanpa aliran deflate yang disiapkan khusus untuk tujuan itu. Akibatnya, pigz menggunakan utas tunggal (utas utama) untuk dekompresi, tetapi akan membuat tiga utas lainnya untuk membaca, menulis, dan memeriksa perhitungan, yang dapat mempercepat dekompresi dalam beberapa keadaan . Namun, seperti Anda, saya menemukan itu setidaknya dua kali lebih cepat daripadagzip
, jika bukan karena paralelismeMasalah dengan semua pipa adalah bahwa Anda pada dasarnya menggandakan pekerjaan. Tidak peduli seberapa cepat dekompresi itu, data masih harus di-shuttled ke proses lain.
Perl memiliki PerlIO :: gzip yang memungkinkan Anda untuk membaca stream gzip secara langsung. Oleh karena itu, itu mungkin menawarkan keuntungan bahkan jika kecepatan dekompresi mungkin tidak cocok dengan
unpigz
:Saya mencobanya dengan file terkompresi 13 MB gzip (didekompresi menjadi 1,4 GB) pada 2010 MacBook Pro lama dengan 16 GB RAM dan ThinkPad T400 lama dengan 8 GB RAM dengan file yang sudah ada dalam cache. Di Mac, skrip Perl secara signifikan lebih cepat daripada menggunakan saluran pipa (5 detik vs 22 detik), tetapi pada ArchLinux, ia kalah karena unpigz:
melawan
dan
Jelas, menggunakan
unpigz -c file.gz | wc -l
adalah pemenang di sini baik dari segi kecepatan. Dan, baris perintah sederhana itu pasti mengalahkan penulisan program, betapapun pendeknya.sumber
gzip | wc
memiliki kecepatan yang sama dari skrip perl Anda. Danpigz | wc
dua kali lipat lebih cepat.gzip
berjalan dengan kecepatan yang sama, terlepas dari apakah saya menulis output ke / dev / null atau pipa kewc
Apa yang saya yakini adalah "pustaka gzip" yang digunakan oleh perl lebih cepat daripada alat baris perintah gzip. Mungkin ada masalah khusus Mac / Darwin lainnya dengan pipa. Masih luar biasa bahwa versi perl ini kompetitif sama sekali.zcat
dan lebih buruk daripadaunpigz
. Saya kagum pada seberapa cepat pipeline pada sistem Linux dibandingkan dengan Mac. Saya tidak mengharapkan itu, meskipun saya seharusnya seperti yang pernah saya amati program yang sama berjalan lebih cepat pada CPU Linux VM terbatas pada Mac yang sama daripada pada bare metal.zcat | wc -l
, dan 5,5 detik untuk skrip perl Anda. Jujur, saya kagum dengan variasi yang dilaporkan orang di sini, terutama antara Linux dan MacOS X!wc -l
dibutuhkan 2,5 detik.gzcat compressed.gz > /dev/null
membutuhkan 2,7 detik. Namun, pipa membutuhkan 22 detik. Jika saya mencoba GNUwc
, hanya membutuhkan setengah detik pada file yang didekompresi, tetapi 22 detik dalam pipa. GNUzcat
membutuhkan waktu dua kali lebih lama untuk dieksekusizcat compressed.gz > /dev/null
. Ini ada di Mavericks, CPU Core 2 Duo lama, 16 GB RAM, SSD MX100 Krusial.Jawaban Kusalananda sebagian besar benar. Untuk menghitung garis, Anda perlu mencari baris baru. Namun secara teori dimungkinkan untuk mencari baris baru tanpa sepenuhnya mengompres file.
gzip menggunakan kompresi DEFLATE. DEFLATE adalah kombinasi dari pengkodean LZ77 dan Huffman. Mungkin ada cara untuk mencari tahu hanya simbol simbol Huffman untuk baris baru dan mengabaikan sisanya. Hampir pasti ada cara untuk mencari baris baru yang dikodekan menggunakan L277, menyimpan jumlah byte dan mengabaikan yang lainnya.
Jadi IMHO secara teoritis dimungkinkan untuk menghasilkan solusi yang lebih efisien daripada unpigz atau zgrep. Itu dikatakan tidak praktis (kecuali seseorang telah melakukannya).
sumber
Dapat dilakukan
zgrep
dengan menggunakan-c
flag, dan$
parameter.Dalam hal ini -c menginstruksikan perintah untuk menampilkan jumlah baris yang cocok dan $ regex cocok dengan akhir baris sehingga cocok dengan setiap baris atau file.
Seperti yang dikomentari oleh @ StéphaneChazelas -
zgrep
hanya sebuah skrip di sekitarzcat
dangrep
dan itu harus memberikan kinerja yang mirip dengan saran asli darizcat | wc -l
sumber
zgrep
umumnya skrip yang memanggilzcat
(sama dengangzip -dcq
) untuk mengompres data dan memberinya makangrep
, jadi tidak akan membantu.Seperti yang Anda lihat, sebagian besar jawaban mencoba untuk mengoptimalkan apa yang dapat dilakukan: jumlah konteks beralih dan IO antar-proses. Alasannya, ini adalah satu-satunya yang dapat Anda optimalkan dengan mudah di sini.
Sekarang masalahnya adalah bahwa kebutuhan sumber dayanya hampir dapat diabaikan untuk kebutuhan sumber daya dekompresi. Inilah sebabnya mengapa optimasi tidak akan benar-benar membuat sesuatu lebih cepat.
Di mana itu bisa benar-benar dipercepat, itu akan menjadi algoritma un-gzip (yaitu dekompresi) yang dimodifikasi, yang meninggalkan produksi aktual dari aliran data yang terkompresi; melainkan hanya menghitung jumlah baris baru dalam aliran yang dikompresi dari yang terkompresi . Akan sulit, itu akan membutuhkan pengetahuan yang mendalam tentang algoritma gzip (beberapa kombinasi dari algoritma kompresi LZW dan Huffman ). Sangat mungkin, bahwa algoritma tidak memungkinkan untuk secara signifikan mengoptimalkan waktu dekompresi dengan keringanan, bahwa kita hanya perlu mengetahui jumlah baris baru. Bahkan jika itu mungkin, pada dasarnya pustaka dekompresi gzip baru seharusnya dikembangkan (tidak ada sebelum diketahui).
Jawaban realistis untuk pertanyaan Anda adalah, tidak, Anda tidak dapat membuatnya lebih cepat secara signifikan.
Mungkin Anda dapat menggunakan beberapa dekompresi gzip paralel, jika ada. Itu bisa menggunakan beberapa core CPU untuk dekompresi. Jika tidak ada, itu bisa relatif mudah dikembangkan.
Untuk xz , ada kompresor paralel (pxz).
sumber