Dosyaları neden ada göre silmek acı verici derecede yavaş ve aynı zamanda son derece hızlı?


11

Sahte pas: Aşağıda bahsettiğim "hızlı" yöntem, yavaş olandan 60 kat daha hızlı değildir. 30 kat daha hızlı. Saatteki hatayı suçlayacağım (3AM, net düşünme için günün en iyi zamanı değil :) ..

Güncelleme: Test sürelerinin bir özetini ekledim (aşağıda).
Hız faktörü ile ilgili iki sorun var gibi görünüyor:

  • Kullanılan komut seçimi (Zaman karşılaştırmaları aşağıda gösterilmiştir)
  • Bir dizindeki çok sayıda dosyanın doğası ... Görünüşe göre "büyük kötü". Sayılar arttıkça işler orantısız bir şekilde yavaşlar.

Tüm testler 1 milyon dosya ile yapılmıştır.
(gerçek, kullanıcı ve sys süreleri test komut dosyalarındadır)
Test komut dosyalarını paste.ubuntu.com adresinde bulabilirsiniz.

#
# 1 million files           
# ===============
#
#  |time   |new dir   |Files added in  ASCENDING order  
#  +----   +-------   +------------------------------------------------- 
#   real    01m 33s    Add files only (ASCENDING order) ...just for ref.
#   real    02m 04s    Add files, and make 'rm' source (ASCENDING order) 
#                      Add files, and make 'rm' source (DESCENDING order) 
#   real    00m 01s    Count of filenames
#   real    00m 01s    List of filenames, one per line
#   ----    -------    ------
#   real    01m 34s    'rm -rf dir'
#   real    01m 33s    'rm filename' via rm1000filesPerCall   (1000 files per 'rm' call)
#   real    01m 40s    'rm filename' via  ASCENDING algorithm (1000 files per 'rm' call)
#   real    01m 46s    'rm filename' via DESCENDING algorithm (1000 files per 'rm' call)
#   real    21m 14s    'rm -r dir'
#   real    21m 27s    'find  dir -name "hello*" -print0 | xargs -0 -n 1000 rm'
#   real    21m 56s    'find  dir -name "hello*" -delete'
#   real    23m 09s    'find  dir -name "hello*" -print0 | xargs -0 -P 0 rm'
#   real    39m 44s    'rm filename' (one file per rm call) ASCENDING
#   real    47m 26s    'rm filename' (one file per rm call) UNSORTED
#                                                       

Kısa süre önce 10 milyon boş test dosyası oluşturdum ve sildim . Dosyaları isme göre isimle (yani rm filename) silerek , 2 farklı yöntem arasında büyük bir zaman farkı olduğunu öğrendim ...

Her iki yöntem de aynı rm filenamekomutu kullanır.

Güncelleme: ortaya çıktığı gibi, komutlar tam olarak aynı değildi ... Bunlardan biri 'rm' için bir seferde 1000 dosya adı gönderiyordu ... Her dosya adının yazıldığını düşündüğüm bir kabuk ayracı genişletme sorunuydu besleyici dosyasına kendi satırında, ancak aslında satır başına 1000'di

Dosya adları bir 'besleyici dosyası' aracılığıyla bir while readdöngüye sağlanır.
Besleyici dosyası çıktısıdır ls -1 -f
Yöntemler tek bir şey hariç tüm yeniden değerlendirmelerde aynıdır:

  • Yavaş yöntem doğrudan sıralanmamış besleyici dosyası kullanırls -1 -f
  • hızlı yöntem aynı ayıklanmamış dosyanın sıralanmış bir sürümünü kullanır

Sıralama burada ths sorunu olup olmadığından emin değilim, ya da belki de sıralanmış besleyici dosyası sadece dosyaların oluşturulduğu sırayla eşleşir mi (basit bir artan tamsayı algoritması kullandım)

1 milyon dosya için, hızlı rm filename yöntem yavaş yöntemden 60 kat daha hızlıdır ... yine, bunun bir "sıralama" sorunu mu yoksa sahne arkasındaki karma tablo sorunu mu bilmiyorum ... bu basit bir sıralama sorunu değildir, çünkü neden bana kasıtlı olarak yeni eklenen "sıralanmış" bir dosya adı dizisinin sıra dışı bir listesini vereyim ... ls -1 -f

Sadece burada neler olduğunu merak ediyorum, bu yüzden önümüzdeki 10 milyon dosyayı silmek günlerimi (evet günler) almıyor :) .... "günler" diyorum çünkü birçok alternatif denedim ve ilgili zamanlar, söz konusu dosyaya orantısız bir şekilde arttı .. bu yüzden sadece 1 milyon ayrıntılı test yaptım

BTW: Dosyaların "sıralı liste" yoluyla silinmesi aslında rm -rf2 katına göre daha hızlı
ve: rm -r"sıralı liste" yönteminden 30 kat daha yavaştı

... ama sorun burada "sıralanıyor" mu? veya daha çok ext4 tarafından kullanılan bir karma (veya her ne olursa olsun) depolama yöntemiyle mi ilgili?

Beni oldukça şaşırtan şey, her çağrının rm filenamebir öncekiyle ilgisiz olmasıdır. (En azından 'bash' perspektifinden bu şekilde)

Ubuntu / bash / 'ext4' / SATA II sürücüsünü kullanıyorum.


1
Yanlış yapıyorsun! (tm) Hiç duydun find -deletemu?
alex

2 testiniz eşit olmayan koşullarda başlar (bunun gerçekten önemli olduğunu iddia etmiyorum): biri dosyadan dosya adlarını okur, diğeri ise testten hemen önce oluşturulmuş (sıralanmış) bir dosyadan dosya adlarını okur. 2. durumda önbelleğe alınan dosya bazı oynatıyor olabilir (ya da belki bilmez). Testlerin daha eşit koşullarda olması için, belki de cat1. testten önce - sort2. testten önce - yeni bir dosyaya basit bir işlem yapmanız gerekir .
imz - Ivan Zakharyaschev

Ve gözlemlerinizi ve sorunuzu daha net bir şekilde sunmanızı tavsiye ederim. Lütfen, her seferinde bir şey: bir soruda sadece 2 vakayı karşılaştırın, iki önemli vakayı ön plana çıkarın, diğer tüm arka plan bilgileri; lütfen bunu açıklığa kavuşturun. Bir gönderide birkaç gözlemi karıştırmayın, lütfen.
imz - Ivan Zakharyaschev

Bulmacayı çözmek için sistem ve kullanıcı alanı zamanını sunmak da önemli olabilir, bu yüzden lütfen bunları sorunuza ekleyin. Bunlardan hangisi testlerinizde büyük fark yaratıyor?
imz - Ivan Zakharyaschev

1
Erken optimizasyon tüm kötülüklerin köküdür. :) 10 Milyon dosya ne zaman silinecek? Saniyede 100 000 bana (sisteminizi mahvetmek için) yeterince hızlı görünüyor.
kullanıcı bilinmiyor

Yanıtlar:


2

rm -r'nin özyinelemeli olarak yavaş olması beklenir. Dizin yapısında bir derinlik ilk geçişi yapılmalıdır.

Şimdi 10 milyon dosyayı nasıl oluşturdunuz? u bazı sipariş döngüleri bazı komut dosyası kullandınız mı? 1.txt, 2.txt, 3.txt ... evetse, bu dosyalar da hdd'deki bitişik bloklarda aynı sırayla tahsis edilebilir. Böylece aynı sırayla silmek daha hızlı olacaktır.

"ls -f" özyinelemeli dizin sırasına göre listelenen -aU'yu etkinleştirir.


1
McAlot: Hiçbir alt dizin olmadığı için bu durumda 'özyinelemeli' 'nin ne kadar önemli olduğunu göremiyorum ... Evet, "1.txt, 2.txt, 3.txt' 'kullandım. Belki birkaç tane var etkileşime giren şeyler: örneğin, 1 milyon dosya oluşturmak neden sadece 1 dakika 30 saniye sürer, ancak 2 milyon oluşturmak 7 dakika sürer ve bunları sildikten sonra 1 milyon çok yeniden oluşturmak tuhaflaşır; her şey çalışıyor; yavaş yavaş aniden .. Bu daha önce de oldu. Sanırım (?) dizini silmek düzeltildi. Dahil bir dosya arka plan programı (nautilus; locate) belki? Devam edecek ...
Peter.O

Genel olarak, dosya sistemleri aynı dizindeki çok sayıda dosyayla başa çıkmak için optimize edilmez. Özellikle ext4'e aşina değilim, ancak diğer biçimler için dosyalar silindiğinde dizin girişleri sadece kullanılmamış olarak işaretlendi. Bu, dizinde işlemler yaparken yine de atlanmaları gerektiği anlamına gelir. Bu, gördüğünüz davranışı açıklar.
KeithB

1
'Şimdi daha yavaş' dizini sildim ve yeni bir dizin için farklı bir ad kullandım. 1 milyon dosya oluşturma zamanı şimdi 1 milyon 33 saniyeye geri döndü (dizin 2 milyon silinen dosyayı "içerdiğinde 9 milyon 30 saniye, ilk milyon yeni eklenen 1 milyonla aynı ada sahip) ... ilginç ve inizle Künyeler "... sadece kullanılmamış olarak işaretlenmiş" açıklama ... orada almak; mantıklı
olmaya başladı

@ fred.bear Kötüüm, gerçek hiyerarşiyi gerçekten bilmiyordum ve cevabım tahmin edildi. Ayrıca testiniz aslında meta verileri vurgular, ancak boş dosyalar oldukları için gerçek dosyaları vurgular. Bu tür bir sorunu karşılaştırmanın en iyi yolu, dosyaları / var veya web sunucusunun önbelleğinden almaktır. Yine de testiniz ilginç geliyor, farklı dizinlerde listelenen iki yöntemle silmeyi deneyebilirsiniz .. /sample1/1.txt,2.txt ... ve /sample2/1.txt,2.txt gibi.
rajaganesh87

@ Mr.Confused.A.Lot ... Yardımın için teşekkürler. Açıklamanız dosya sistemi ve bazı davranış biçimleri hakkında daha fazla anlamama yardımcı oldu ... Şimdi farklı hız sorunlarına neyin sebep olduğuna dair makul bir fikrim var ... bazıları sadece bash komutlarının seçimi ve diğerleri sadece dosya sistemi sorunlarıydı ( Yeni bir sloganla kaldım: Dizinler için "büyük kötü" ... (en azından bazı eylemler için) ...
Peter.O

2

Dosya yapısını optimize etmelisiniz. Yani yerine

for i in $(seq 1 1000); do touch file.$i; done

daha akıllıca bir şey yap (bash varsayılır):

function bucklocate() 
{ 
    hash=$(echo -n "$1"|md5sum|cut -f1); 
    echo -n "${hash:1:1}/${hash:7:1}/${hash:9:2}/$1"; 
}

hexdig="{0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f}"
eval mkdir -p $hexdig/$hexdig/$hexdig$hexdig


for i in $(seq 1 1000); do touch $(bucklocate file.$i); done

Şimdi bu örnek, md5sum [1] kullanımı nedeniyle oldukça yavaştır, herhangi bir dosya adına ihtiyacınız olmadığı sürece, kopyaların endişe duymadığı ve belirli bir ismin tekrarlanabilir karması :)

mkdir -pv {0,1,2,3,4,5,6}/{0,1,2,3,4,5,6,7,8,9,10,12}
for  a in $(seq 1 100); do i=$RANDOM; echo touch "$(($i%7))/$(($i%13))/file.$i"; done

Tabii ki bu tüm hashtables kavramları özensiz ödünç


Sanırım "daha küçük dizinler kullan" diyorsun ... Bu çok ilginç bir fikir; "Ağaçsız" bir dosya grubundan bir ağaç yapan bir evde yetişen DBMS ". Bazıları ileriye dönük planlama diyebilir :) ... Çalışırsa (ve muhtemelen işe yarıyorsa), iyi bir fikirdir ! ... bir dizindeki (en azından ext4 için) dosya sayısına gelince 'büyük kötü' fikrini almaya başlıyorum ... Önleyici bir geçici çözüm sundunuz (+1) ve ben ' yavaş yavaş herhangi bir dizinde bazı silme yöntemlerinin diğerlerinden daha hızlı neden bir fikir alıyorum; küçük veya büyük ... Teşekkürler
Peter.O

Yup dirs küçük tutmak fikri hakkında daha açık olmadığı için üzgünüm
sehe
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.