2014-12-28 30 views
1

我有一個關於使用BlockingCollection和Dictionary編寫代碼的問題。BlockingCollection和Dictionary

我的目標是讀取一堆文本文件並以並行方式處理它們。已處理的數據將存儲在BlockingCollection實例中,以便可以將這些已處理的數據寫入文件。

我爲什麼要使用BlockingCollection的原因是...

(1),以節省時間,而GenerateDataFiles()是做CPU密集型的工作和消費任務可以做IO相關工作在此期間,和

(2)與將所有處理過的數據寫入列表之前將其中的任何一個寫入文件之前相比,以減少內存使用量。對於(2),如果我在將所有數據寫入文件之前先存儲所有數據,則內存消耗量超過了我的桌面所能承受的數量(因爲它讀取的數據超過30GB),所以我必須使用此生產者 - 消費者的方法。

另外,我在將BlockingCollection實例(或字典)中的鍵值對插入時遇到了問題。請指出進行數據插入的正確方法。

下面的代碼是我試圖解決這個問題的。由於我是BlockingCollection的新手,因此我可能在這方面犯了一些錯誤。請提出一些更改(和修改代碼),以便我可以解決問題。

class SampleClass 
{ 
    static void Main(string[] args) 
    {    
     SampleClass sampleClass = new SampleClass(); 
     sampleClass.run(); 
    } 

    private void run() 
    { 
     Task consumer = Task.Factory.StartNew(() => WriteDataToFiles()); 
     GenerateDataFiles(); 
    } 

    BlockingCollection<Dictionary<string, List<string>>> bc = new BlockingCollection<Dictionary<string, List<string>>>(); 

    private void GenerateDataFiles() 
    { 
     DirectoryInfo directory = new DirectoryInfo(@"D:\Data\"); 
     FileInfo[] array_FileInfo = directory.GetFiles("*.txt", SearchOption.TopDirectoryOnly); 

     Parallel.ForEach(array_FileInfo, fileInfo => 
     { 
      string[] array_Lines = File.ReadAllLines(fileInfo.FullName); 

      // do some CPU-intensive data parsing and then add the processed data to the blocking collection 
      // It has to be inserted in pairs (key = file path, value = list of strings to be written to this file) 

     }); 
    } 

    private void WriteDataToFiles() 
    { 
     foreach (var item in bc.GetConsumingEnumerable()) 
     { 
      foreach (var key in item.Keys) 
      { 
       File.WriteAllLines(key, item[key]); 
      } 
     } 

    } 
} 
+0

備註 - 編寫IO的多個實例會導致應用程序性能降低,特別是在使用機械HD時。另外,我沒有看到你將任何數據插入到'BlockCollection'中。 –

+0

@YuvalItzchakov爲什麼我沒有包含將數據插入到BlockingCollection的代碼的原因是我在VS中編寫的語法顯示錯誤。這就是爲什麼我把它留空而不是寫點東西來混淆別人。 – Roy

+0

在'Parallel.ForEach'中運行代碼仍然會導致你的進程膨脹,因爲當你使用'File.ReadAllLines'時,你不會從集合中取出任何項目。 –

回答

1

考慮使用Tuple代替DictionaryBlockingCollection內。此外,您需要致電CompleteAdding()以結束foreachWriteDataToFiles

BlockingCollection<Tuple<string, List<string>>> bc = new BlockingCollection<Tuple<string, List<string>>>(); 

private void GenerateDataFiles() 
{ 
    DirectoryInfo directory = new DirectoryInfo(@"D:\Data\"); 
    FileInfo[] array_FileInfo = directory.GetFiles("*.txt", SearchOption.TopDirectoryOnly); 

    Parallel.ForEach(array_FileInfo, fileInfo => 
    { 
     string[] array_Lines = File.ReadAllLines(fileInfo.FullName); 

     // do some CPU-intensive data parsing and then add the processed data to the blocking collection 
     // It has to be inserted in pairs (key = file path, value = list of strings to be written to this file) 
     List<string> processedData = new List<string>(); // ... and add content 
     bc.Add(new Tuple<string, List<string>>(fileInfo.FullName, processedData)); 
    }); 
    bc.CompleteAdding(); 
} 

private void WriteDataToFiles() 
{ 
    foreach (var tuple in bc.GetConsumingEnumerable()) 
    { 
     File.WriteAllLines(tuple.Item1, tuple.Item2); 
    } 
}