2010-06-02 41 views
2

以下代碼將創建正確數量的文件,但每個文件都包含第一個列表的內容。任何人都可以發現我做錯了嗎?使用並行任務庫時'foreach'失敗

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

讓我們看看你WriteListToLogFile方法 – VoodooChild 2010-06-02 09:33:38

回答

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

你真的不應該使用Parallel.ForEach而不是foreach。這對於做一些像啓動任務一樣輕量級的東西來說效率很低。請參閱我的答案以獲得解釋。 – 2010-07-01 07:09:17

0

我不確定爲什麼你有一個「任務」列表,你只能使用其中的一個。

編輯: factory.StartNew創建並啓動System.Threading.Tasks.Task!

大聲思考: 因此,在其列表中調用WriteListToLogFile的每個List<String>都有一個單獨的任務?

我想你會需要使用

ThreadPool.QueueUserWorkItem 

在你的代碼task.Add後,在這個例子中

看(見接受的答案後)link

+1

您沒有正確讀取的代碼。 factory.StartNew(...)爲列表集合中的每個項目創建並啓動一個新的Task。 – 2010-06-02 09:48:01

+0

+1好我現在看到我的錯誤:)謝謝! var聲明讓我感到困惑。 – VoodooChild 2010-06-02 09:59:22

+0

ThreadPool是進行並行編程的舊方法,並不會像新的並行任務庫那樣給出儘可能多的反饋和控制。 – 2010-06-02 11:23:55

0

就遇到了這個同樣的問題我。我真不知道爲什麼會發生,但我可以得到它通過傳遞一個狀態對象

foreach (var list in lists) 
    { 
    tasks.Add(factory.StartNew((o) => 
    { 
     var l = o as List<string>; 
     WriteListToLogFile(l); 
    }, list)); 
    } 
+1

您不應該使用狀態對象。看到我的回答/解釋。 – 2010-07-01 07:11:17

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<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

相關問題