我有一个关于使用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 :(得分: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);
}
}