2014-12-28 2 views
1

У меня вопрос о написании кодов с использованием BlockingCollection и Dictionary.BlockingCollection и словарь

Моя цель - прочитать кучу текстовых файлов и обработать их параллельно. Обработанные данные будут храниться в экземпляре BlockingCollection, чтобы эти обработанные данные могли быть записаны в файл.

Причины, почему я хочу использовать BlockingCollection это ...

(1), чтобы сэкономить время, пока GenerateDataFiles() делает процессор интенсивной работы и потребительские задачи могут сделать IO соответствующей работу в то же время , и

(2) уменьшить использование памяти по сравнению с случаем, когда я храню все обработанные данные в списке перед записью любого из них в файл.

Для (2), если я храню все данные перед их записью в файл, потребление памяти больше, чем мой рабочий стол может позволить себе (поскольку он читает более 30 ГБ данных), и поэтому я должен использовать этого производителя - потребительский подход.

Также у меня возникла проблема при вставке пары ключ-значение в экземпляр 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 вместо Dictionary внутри BlockingCollection. Кроме того, вам необходимо позвонить в CompleteAdding(), чтобы положить foreach в WriteDataToFiles.

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); 
    } 
} 
Смежные вопросы