2

以下代码创建了正确数量的文件,但每个文件都包含第一个列表的内容。谁能发现我做错了什么?

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());
}
4

4 回答 4

4

原因在于 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);
    }));
} 

您不必将列表值显式传递给匿名方法。

这篇博客文章更详细地介绍了这一点:

http://blogs.msdn.com/b/abhinaba/archive/2005/10/18/482180.aspx

于 2010-07-01T07:07:20.100 回答
1

很抱歉没有早点回复这个问题。我找到了一个解决方案 - 虽然我不明白它为什么会起作用......

原来,我有这个...

foreach (var list in lists)
  {
    tasks.Add(factory.StartNew(() =>
    {
      WriteListToLogFile(list);
    }));
  }

将顺序 foreach 更改为并行 foreach 可以解决问题...

Parallel.ForEach<string>(lists, list =>
    tasks.Add(factory.StartNew(() =>
    {
      WriteListToLogFile(list);
    }));
  );
于 2010-06-17T13:52:26.497 回答
0

我不确定你为什么有一个“任务”列表,你只使用过其中一个。

编辑: factory.StartNew 创建并启动 System.Threading.Tasks.Task!!

大声思考:所以List<String>列表中的每个调用 WriteListToLogFile 都有一个单独的任务?

我想你需要使用

ThreadPool.QueueUserWorkItem 

在任务之后的代码中。添加

查看此示例(请参阅已接受的答案帖子) 链接

于 2010-06-02T09:36:59.123 回答
0

我自己也遇到了同样的问题。我仍然不确定它为什么会发生,但我能够通过传入一个状态对象让它正常工作

 foreach (var list in lists) 
  { 
    tasks.Add(factory.StartNew((o) => 
    { 
      var l = o as List<string>;
      WriteListToLogFile(l); 
    }, list)); 
  } 
于 2010-06-16T21:33:21.220 回答