Döngü ve genleşme performansı


9

Aşağıdaki karşılaştırma konusunda uzman önerilerine ihtiyacınız var:

Döngü kullanarak Kod Segmenti:

for file in `cat large_file_list`
do
    gzip -d $file
done

Basit genişletme kullanarak kod segmenti:

gzip -d `cat large_file_list`

Hangisi daha hızlı olacak? Büyük veri kümesini değiştirmek zorundasınız.


1
Doğru yanıt, gzipsisteminizde ne kadar sürede başlayacağına , dosya listesindeki dosya sayısına ve bu dosyaların boyutuna bağlıdır.
Kusalananda

Dosya listesinde yaklaşık 1000 - 10000 dosya bulunur. Boyut bazı kilobaytlardan 500 MB'a kadar değişir. Sistemimde gzip'i başlatmanın ne kadar süreceği hakkında hiçbir fikrim yok . herhangi bir şekilde kontrol?
Leon

1
Tamam, o zaman dosya adlarının uzunluğuna da bağlı olabilir . Dosya adları uzunsa, komut değiştirme işlemi kabuğun yürütülmesi için çok uzun bir komut satırına neden olacağından, döngü olmadan yapmaya çalıştığınızda bazı sistemler "bağımsız değişken listesi çok uzun" hatası oluşturabilir. Listedeki dosya sayısına bağlı kalmak istemiyorsanız, bir döngü kullanın. Bu dosyaları, üzerinde gerçekleştireceğiniz diğer işlemlerle karşılaştırıldığında önemli miktarda zaman harcıyor musunuz?
Kusalananda

Leon test sonuçlarıma bir göz atın: "dev-arglist" benim ayarımda "loop" dan 20 kat daha hızlı.

işlem başlangıcı ve komut satırı uzunluğu arasında mutlu bir ortam xargs gzip -d < large_file_listiçin, dosya adlarındaki boşluklara dikkat edin, ancaktr \\n \\0 large_file_list | xargs -0 gzip -d
w00t

Yanıtlar:


19

Komplikasyonlar

Aşağıdakiler yalnızca bazen çalışacaktır:

gzip -d `cat large_file_list`

Üç problem vardır ( bashBourne benzeri mermilerin çoğunda ve çoğu):

  1. Herhangi bir dosya adında boşluk sekmesi veya yeni satır karakterleri varsa ( $IFSdeğiştirilmediğini varsayarsak ) başarısız olur . Bu, kabuğun kelime bölünmesinden kaynaklanmaktadır .

  2. Herhangi bir dosya adında glob etkin karakterler varsa da başarısız olabilir. Bunun nedeni kabuğun dosya listesine yol adı genişletmesi uygulayabilmesidir .

  3. Dosya adları ile başlıyorsa -( POSIXLY_CORRECT=1bu yalnızca ilk dosya için geçerliyse) veya herhangi bir dosya adı ise başarısız olur -.

  4. Bir komut satırına sığmayacak kadar çok dosya adı varsa da başarısız olur.

Aşağıdaki kod, yukarıdaki kodla aynı sorunlara tabidir (dördüncü hariç)

for file in `cat large_file_list`
do
    gzip -d $file
done

Güvenilir çözüm

large_file_listHer satırda tam olarak bir dosya adınız varsa ve adında bir dosya -aralarında değilse ve bir GNU sisteminde iseniz, şunu kullanın:

xargs -rd'\n' gzip -d -- <large_file_list

-d'\n'xargsher girdi satırına ayrı bir dosya adı olarak davranılmasını söyler .

-rxargsgirdi dosyası boşsa komutu çalıştırmamayı söyler .

--gzip, aşağıdaki argümanların başlasalar bile seçenek olarak ele alınmaması gerektiğini söyler -. -tek başına yine de -denilen dosya yerine muamele olurdu -.

xargsher komut satırına çok sayıda dosya adı koyar, ancak komut satırı sınırını aşacak kadar çok dosya adı koyamaz. Bu, bir gzipişlemin kaç kez başlatılması gerektiğini azaltır ve bu nedenle bunu hızlı hale getirir. Ayrıca güvenlidir: dosya adları sözcük bölme ve yol adı genişletme işlemlerinden de korunacaktır .


Ayrıntılı cevap için teşekkürler. Bahsettiğiniz 3 konuyu anlıyorum. Dosya adı basittir ve liste 20000'e kadar çıkacağı için bu zorluklarla yüzleşmeyecektir. Benim sorum temelde bu iki segmentin performansıyla ilgili. Teşekkürler.
Leon

1
@Leon forDöngü - en yavaş - en yavaş olacak. Diğer iki yöntem hız açısından birbirine çok yakın olacaktır.
John1024

7
Ayrıca, olası sorunları da göz ardı etmeyin: StackExchange ile ilgili birçok soru, kelime ayırma veya yol adı genişletmesinin , beklemeyen insanlara gerçekleşmesidir.
John1024

5
Ayrıca aşağıdakileri içeren bir dosyayı okumada bir değişiklik olduğunu unutmayın xargs: en azından GNU sürümü --arg-fileseçeneği (kısa form -a) vardır. Bunun xargs -a large_file_list -rd'\n' gzip -d yerine kişi yapabilirdi. Etkili bir şekilde <, kabuk operatörü ve xargsstdin'den (hangi kabuk "dosyaya" kabuk) okuma yapmak gerçeği dışında hiçbir fark yoktur, söz konusu dosyayı açıkça açık -ayapacakxargs
Sergiy Kolodyazhnyy

2
terdon, parallelbirden fazla kopyasını çalıştırmak için kullanmakla ilgili başka bir yorumda belirtildi gzip, ancak xargs(en azından GNU olanı) bunun da -Panahtarı var. Fark yaratabilecek çok çekirdekli makinelerde. Ancak, dekompresyonun tamamen G / Ç'ye bağlı olması da mümkündür.
ilkkachu

12

Çok önemli olacağından şüpheliyim.

Liste dosyasında kaç dosya listelendiğini bilmediğim için bir döngü kullanırdım ve dosya adlarından herhangi birinin adlarında boşluk olup olmadığını bilmiyorum (genellikle). Çok uzun bir argüman listesi oluşturacak bir komut değişikliği yapmak, oluşturulan listenin uzunluğu çok uzun olduğunda "Bağımsız değişken listesi çok uzun" hatasına neden olabilir.

Döngüm şöyle görünecekti

while IFS= read -r name; do
    gunzip "$name"
done <file.list

Bu ayrıca, gunzipkomuttan sonra verileri işlemek için komutlar eklememe izin verir . Aslında, verinin gerçekte ne olduğuna ve onunla ne yapılması gerektiğine bağlı olarak, hiç bir dosyaya kaydetmeden işlemek bile mümkün olabilir:

while IFS= read -r name; do
    zcat "$name" | process_data
done <file.list

( process_datasıkıştırılmamış verileri standart girdiden okuyan bir boru hattı nerede )

Verilerin işlenmesi sıkıştırılmamasından daha uzun sürerse, bir döngünün daha verimli olup olmadığı sorusu önemsiz hale gelir.

İdeal olarak , bir dosya adları listesini çalışmamayı tercih ederim ve bunun yerine bir dosya adı globbing kalıbı kullanmayı tercih ederim.

for name in ./*.gz; do
    # processing of "$name" here
done

Burada ./*.gz, ilgili dosyalarla eşleşen bir model var. Bu şekilde dosya sayısına veya dosya adlarında kullanılan karakterlere bağlı değiliz (yeni satırlar veya diğer boşluk karakterleri içerebilir veya çizgilerle başlayabilir vb.)

İlişkili:


5

Bu ikisinden, tüm dosyaları tek bir çağrışmaya geçiren dosya gzipdaha hızlı olacaktır, çünkü tam olarak yalnızca bir gzipkez başlatmanız gerekir . (Yani, komut hiç işe yaramazsa, uyarılar için diğer yanıtlara bakın.)

Ancak, optimizasyonun altın kuralını hatırlatmak isterim : Bunu erken yapmayın.

  1. Sorun olduğunu bilmeden bu tür şeyleri optimize etmeyin.

    Programın bu kısmı uzun sürüyor mu? Eh, büyük dosyaların sıkıştırmasını açmak ve yine de yapmanız gerekecek, bu yüzden cevaplamak o kadar kolay olmayabilir.

  2. Ölçün. Gerçekten, emin olmanın en iyi yolu.

    Sonuçları kendi gözlerinizle (veya kendi kronometrenizle) görürsünüz ve durumunuza internette rastgele cevapların veremeyeceği durumlar için geçerli olurlar . Komut ve vadede hem varyantları koyun time script1.shve time script2.sh. (Bunu, ek yükün mutlak miktarını ölçmek için boş sıkıştırılmış dosyaların bir listesiyle yapın.)


0

Diskiniz ne kadar hızlı?

Bu işlem tüm CPU'larınızı kullanmalıdır:

parallel -X gzip -d :::: large_file_list

Yani sınırınız muhtemelen diskinizin hızı olacaktır.

Ayarlamayı aşağıdakilerle deneyebilirsiniz -j:

parallel -j50% -X gzip -d :::: large_file_list

Bu, işlerin yarısını önceki komutla paralel olarak çalıştıracak ve diskinizi daha az vurgulayacaktır, bu nedenle diskinize bağlı olarak bu daha hızlı olabilir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.