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を出力します。これはyoyが期待するものではありません

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

リスト値をanonymousメソッドに明示的に渡す必要はありません。

このブログ投稿では、これについてさらに詳しく説明しています。

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

「タスク」のリストがある理由はわかりません。使用しているのはそのうちの1つだけです。

編集:factory.StartNewSystem.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 に答える