我有一个返回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
答案 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
的东西。