2016-02-12 21 views
5

Büyük bir dosya satırını okuyan, onunla bir mantık oluşturan ve bir dosyaya yazmam gereken bir dize döndüren bir görevim var. Çıkışın sırası önemli değil. Ancak, aşağıdaki kodu denediğimde, dosyamın 15-20k satırlarını okuduktan sonra durur/yavaşlar.Parallel.ForEach kullanarak bir dosyaya nasıl doğru yazılır?

public static Object FileLock = new Object(); 
... 
Parallel.ForEach(System.IO.File.ReadLines(inputFile), (line, _, lineNumber) => 
{ 
    var output = MyComplexMethodReturnsAString(line); 
    lock (FileLock) 
    { 
     using (var file = System.IO.File.AppendText(outputFile)) 
     { 
      file.WriteLine(output); 
     } 
    } 
}); 

Programım neden bir süre çalıştıktan sonra yavaşlıyor? Bu görevi gerçekleştirmenin daha doğru bir yolu var mı?

+0

Eğer karşılık gelecek şekilde çıkış hatlarının sırasını mi istiyorsunuz:

Hızlı bir geçici çözüm, ParallelOptions kabul şöyle aşırı kullanarak, askere izin parçacığı Parallel.ForEach sayısını sınırlamak için giriş sırası? Eğer öyleyse, 'Parallel.ForEach' doğru araç değildir. – adv12

+0

Hayır, çıktı çizgilerinin sırası önemli değil. – justindao

+1

Emin değilim, ancak bu şekilde paralel kullanılmasının, onu önlemek yerine IO darboğazını yarattığı/kötüleştirdiğini hissediyorum. Bu satırlarda __really pahalı__ işlemleri yapıyorsanız .. – TaW

cevap

4

Tüm ileti dizilerinin dosyaya yazılmasını sağlayarak, sorgunuzu dizileştirdiniz. Bunun yerine, neyin yazılması gerektiğini hesaplamalısınız, sonunda geldikleri gibi yazmalısınız.

var processedLines = File.ReadLines(inputFile).AsParallel() 
    .Select(l => MyComplexMethodReturnsAString(l)); 
File.AppendAllLines(outputFile, processedLines); 

bunu geldiği gibi, veri temizleme akışı açıp (elle veya gömme) oto kızarma etkinleştirmeniz gerekiyorsa: Bu nasıl Parallel.ForEach 'ın iç yük dengeleyici ile ilgisi var

var processedLines = File.ReadLines(inputFile).AsParallel() 
    .Select(l => MyComplexMethodReturnsAString(l)); 
using (var output = File.AppendText(outputFile)) 
{ 
    output.AutoFlush = true; 
    foreach (var processedLine in processedLines) 
     output.WriteLine(processedLine); 
} 
+0

dosya gerçekten dosya varsa, bu yaklaşım yeterli olduğundan emin değilim, çünkü tüm dosya bir ilk adımı okumayı gerektirir. –

+0

'File.ReadLines()' kullanıldığında, okunan bir dosyanın satırlarında numaralandırabileceğiniz bir numara verir. Bu, 'Dosya'nın kullanılmasının tersidir.Bir dosyanın tüm satırlarını içeren bir dizi döndüren ReadAllLines(). _That_ tüm dosyada okur. –

1

Eserleri. Konularınızın çok fazla zaman harcadığını gördüğü zaman, sorunla ilgili daha fazla iş parçacığı atayarak, FileLock için daha yüksek paralel yüklere, çekişmeye ve genel performans düşüşüne neden olarak işleri hızlandırabilmesinin nedenleri.

neden oluyor? Parallel.ForEach, IO çalışması için kullanılmadığı için.

Bunu nasıl düzeltebilirsiniz? Yalnızca CPU çalışması için Parallel.ForEach kullanın ve tüm IO'yu paralel döngü dışında gerçekleştirin.

Parallel.ForEach(
    System.IO.File.ReadLines(inputFile), 
    new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount }, 
    (line, _, lineNumber) => 
    { 
     ... 
    } 
+0

Cevabınızı "Hızlı bir çözüm ..." ye kadar gerçekten çok seviyorum. Önceden söylediğin her şeyden geriye doğru bir adım gibi görünüyor. Belki de kodu çözdüyseniz bana daha mantıklı gelecektir. – Enigmativity

+0

Meraklı: Environment.ProcessorCount'un zaten MaxDegreeOfParallelism için doğal sınır olduğunu varsaymıştım. Yanlış mı? – TaW

+1

@TaW, hayır, "Environment.ProcessorCount" un ötesine geçecek. Burada, işlemi öldürdüğünüzde (saniyeden sonra vazgeçtim) saniyede 1 iş parçacığı ekleyen bir keman var: https://dotnetfiddle.net/dT1eBM (söylemeye gerek yok, muhtemelen bunu üretiminizde çalıştırmamalısınız) sunucusu) –

İlgili konular