如何让多个线程处理相同的IEnumerable结果?

时间:2011-02-23 04:43:17

标签: c# ienumerable task

我有一个返回IEnumerable<string>的方法,当然正在处理yield return <string>;。我希望有多个线程处理这个结果,当然不重复它并且是线程安全的。我怎么做到这一点?

var result = GetFiles(source);

for (int i = 0; i < Environment.ProcessorCount; i++)
{
    tasks.Add(Task.Factory.StartNew(() => { ProcessCopy(result); }));
}

Task.WaitAll(tasks.ToArray());

然而,这似乎产生了重复:

C:\Users\esac\Pictures\2000-06\DSC_1834.JPG
C:\Users\esac\Pictures\2000-06\DSC_1835.JPG
C:\Users\esac\Pictures\2000-06\.picasa.ini
C:\Users\esac\Pictures\2000-06\DSC_1834.JPG
C:\Users\esac\Pictures\2000-06\DSC_1835.JPG
C:\Users\esac\Pictures\2000-06\.picasa.ini
C:\Users\esac\Pictures\2000-06\DSC_1834.JPG
C:\Users\esac\Pictures\2000-06\DSC_1835.JPG
C:\Users\esac\Pictures\2000-06\.picasa.ini
C:\Users\esac\Pictures\2000-06\DSC_1834.JPG
C:\Users\esac\Pictures\2000-06\DSC_1835.JPG

3 个答案:

答案 0 :(得分:9)

您可以使用Parallel.ForEach方法轻松完成此操作。

Write a Simple Parallel.ForEach loop

每次迭代都将在任务管理器中排队。执行所有迭代后,循环将退出。

var result = GetFiles(source);

Parallel.ForEach(result, current => {
    ProcessCopy(current);
});

Console.WriteLine("Done");

答案 1 :(得分:4)

您必须为每个ProcessCopy()调用选择一系列项目 - 现在您正在为每个线程传递完整的文件枚举 - 请记住,您传递的IEnumerable有一个名为{{的方法1}} - 只有当调用该方法时(foreach为你做了这个方法)才会返回真正的枚举器,然后您可以逐个枚举这些项目。由于您传递GetEnumerator()每个线程正在调用IEnumerable,因此枚举所有文件。

而是做这样的事情让每个GetEnumerator()处理一个文件:

ProcessCopy()

我不担心处理器数量 - 让TPL和线程池计算出运行多少线程以获得最佳性能。

答案 2 :(得分:1)

为什么不使用简单的LINQ查询来做你想做的事?

var tasks =
    from f in GetFiles(source)
    select Task.Factory.StartNew(() => { ProcessCopy(f); });

Task.WaitAll(tasks.ToArray());

在幕后,TPL会为你处理所有ick Environment.ProcessorCount的东西。