`使用Parallel.ForEach加速文件处理但不能以正确的顺序返回

时间:2015-08-21 11:30:11

标签: c# parallel-processing

所以即时尝试使用Parallel.ForEach循环来加速我对文件的处理,但我无法弄清楚如何使它以有序的方式构建输出。这是我到目前为止的代码:

string[] lines = File.ReadAllLines(fileName);
List<string> list_lines = new List<string>(lines);

Parallel.ForEach(list_lines, async line =>
{
    processedData += await processSingleLine(line);
});

你可以看到它没有任何有序的实施,因为我已经尝试寻找适合我的解决方案的东西我还没有发现任何我能够得到的东西工作。
所以我最好还是要处理每一行但是按照每行发出的相同顺序构建processedData变量,但是我确实知道这可能只是超出了我目前的技能水平所以任何建议会很好。

编辑: 在尝试阅读下面的答案后,我尝试了两种方法:

ConcurrentDictionary<int, string> result = new ConcurrentDictionary<int, string>();
Parallel.For(0, list.Length, i =>
{
    // process your data and save to dict
    result[i] = processData(lines[i]);
});

ConcurrentDictionary<int, string> result = new ConcurrentDictionary<int, string>();
for (var i = 0; i < lines.Length; i++)
{
    result[i] = lines[i];
}
Array.Clear(lines,0, lines.Length);
Parallel.ForEach(result, line =>
{
    result[line.Key] = encrypt(line.Value, key);
});

然而,两者似乎只使用了大约1个核心(4个核心处理器),占任务管理器总数的30%,而之前我实现了它在CPU上接近80%的使用顺序。

3 个答案:

答案 0 :(得分:2)

您可以尝试使用Parallel.For代替Parallel.ForEach。然后你将有你的线索引。即:

string[] lines = File.ReadAllLines(fileName);

// use thread safe collection for catching the results in parallel
ConcurrentDictionary<int, Data> result = new ConcurrentDictionary<int, Data>();

Parallel.For(0, list.Length, i =>
{
    // process your data and save to dict
    result[i] = processData(lines[i]);
});

// having data in dict you can easily retrieve initial order
Data[] orderedData = Data[lines.Length];
for(var i=0; i<lines.Length; i++)
{
    orderedData[i] = result[i];
}

编辑:正如您在问题的评论中所说,您不能在此处使用异步方法。当你这样做时,Parallel.ForEach将返回一堆任务,而不是结果。如果要并行化异步代码,可以使用多个Task.Run,如下所示:

string[] lines = File.ReadAllLines(fileName);

var tasks = lines.Select(
                 l => Task.Run<Data>(
                         async () => {
                              return await processAsync(l);
                         })).ToList();

var results = await Task.WhenAll(tasks);

注意:应该有效,但没有检查。

答案 1 :(得分:1)

我相信Parallel.ForEach.AsOrdered()做你想要的。

答案 2 :(得分:1)

从代码中获取数据结构 list_lines 和方法 processSingleLine ,以下内容应该保留顺序并执行并行:

var parallelQuery = from line in list_lines.AsParallel().AsOrdered()
                    select processSingleLine(line);

foreach (var processedLine in parallelQuery)
{
    Console.Write(processedLine);
}