以下代码创建正确数量的文件,但每个文件都包含第一个列表的内容。谁能发现我做错了什么吗?
private IList<List<string>> GetLists()
{
// Code omitted for brevity...
}
private void DoSomethingInParallel()
{
var lists = GetLists();
var tasks = new List<Task>();
var factory = new TaskFactory();
foreach (var list in lists)
{
tasks.Add(factory.StartNew(() =>
{
WriteListToLogFile(list);
}));
}
Task.WaitAll(tasks.ToArray());
}
最佳答案
原因在于 C# 评估匿名方法的方式,它们不是真正的闭包。这确实与TPL无关。以下代码打印出所有 d。这不是你所期望的
List<Task> tasks = new List<Task>();
List<string> lists = new List<string>();
lists.AddRange(new string[] { "a", "b", "c", "d" });
foreach (var list in lists)
{
tasks.Add(Task.Factory.StartNew(() =>
{
Console.WriteLine(list);
}));
}
原因是因为创建匿名方法时list的值不是在方法主体中计算的值。使用方法执行时list的值。您可以通过执行以下操作强制修复此问题:
List<Task> tasks = new List<Task>();
List<string> lists = new List<string>();
lists.AddRange(new string[] { "a", "b", "c", "d" });
foreach (var list in lists)
{
var localList = list;
tasks.Add(Task.Factory.StartNew(() =>
{
Console.WriteLine(localList);
}));
}
您不必显式地将列表值传递给匿名方法。
这篇博文对此进行了更详细的介绍:
关于.net-4.0 - 使用并行任务库时“foreach”失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2956328/