C# BlockingCollection和Dictionary

C# BlockingCollection和Dictionary,c#,dictionary,blockingcollection,C#,Dictionary,Blockingcollection,我有一个关于使用BlockingCollection和Dictionary编写代码的问题 我的目标是读取一堆文本文件并以并行方式处理它们。处理后的数据将存储在BlockingCollection实例中,以便将这些处理后的数据写入文件 我想使用BlockingCollection的原因是 (1) 为了节省时间,GenerateDataFiles()正在执行CPU密集型工作,而使用者任务可以同时执行IO相关工作,以及 (2) 与将所有处理过的数据写入文件之前将其存储在列表中的情况相比,可以减少内存使

我有一个关于使用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]);
            }
        }

    }
}
class-SampleClass
{
静态void Main(字符串[]参数)
{            
SampleClass SampleClass=新的SampleClass();
sampleClass.run();
}
私家车
{
任务使用者=Task.Factory.StartNew(()=>writeDataofiles());
GenerateDataFiles();
}
BlockingCollection bc=新BlockingCollection();
私有void GenerateDataFiles()
{
DirectoryInfo directory=newdirectoryinfo(@“D:\Data\”);
FileInfo[]数组_FileInfo=directory.GetFiles(“*.txt”,SearchOption.TopDirectoryOnly);
Parallel.ForEach(数组_FileInfo,FileInfo=>
{
string[]array\u Lines=File.ReadAllLines(fileInfo.FullName);
//执行一些CPU密集型数据解析,然后将处理后的数据添加到阻塞集合
//它必须成对插入(键=文件路径,值=要写入此文件的字符串列表)
});
}
私有无效写入状态文件()
{
foreach(bc.GetConsumingEnumerable()中的变量项)
{
foreach(item.Keys中的变量键)
{
File.writeAllines(key,item[key]);
}
}
}
}

考虑在
BlockingCollection
中使用
元组
而不是
字典
。此外,还需要调用
completedadding()
,以结束
writedatafiles
中的
foreach

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);
    }
}
BlockingCollection bc=new BlockingCollection();
私有void GenerateDataFiles()
{
DirectoryInfo directory=newdirectoryinfo(@“D:\Data\”);
FileInfo[]数组_FileInfo=directory.GetFiles(“*.txt”,SearchOption.TopDirectoryOnly);
Parallel.ForEach(数组_FileInfo,FileInfo=>
{
string[]array\u Lines=File.ReadAllLines(fileInfo.FullName);
//执行一些CPU密集型数据解析,然后将处理后的数据添加到阻塞集合
//它必须成对插入(键=文件路径,值=要写入此文件的字符串列表)
List processedData=new List();/…并添加内容
Add(新元组(fileInfo.FullName,processedData));
});
完成添加();
}
私有无效写入状态文件()
{
foreach(bc.getconsumineGenumerable()中的变量元组)
{
writeAllines文件(tuple.Item1,tuple.Item2);
}
}

旁注-编写多个IO实例会导致应用程序性能降级,尤其是在使用mechanical HD时。此外,我没有看到您将任何数据插入到
BlockCollection
@YuvalItzchakov。我没有将代码插入BlockingCollection的原因是我在VS中编写的语法显示错误。这就是为什么我将其留空,而不是编写一些东西来迷惑其他人。以
并行方式运行代码。ForEach
仍然会导致进程膨胀,因为当您使用
File.ReadAllLines
时,您没有从集合中取消任何项目的排队。算了吧。使用
Directory.EnumerateFiles()
File.ReadLines()
编写顺序版本真正的问题是一些CPU密集型数据解析,它是否需要内存中的所有文件和所有行?