2012-01-11 43 views
2

我有一個方法返回XML元素,但該方法需要一些時間才能完成並返回一個值。在c#中同時運行多個方法

我現在有什麼是

foreach (var t in s) 
{ 
    r.add(method(test)); 
} 

但這只是前一個完成後運行的下一條語句。我怎樣才能讓它同時運行?

+0

是'r'和'add'和'method'和'test'線程安全的? – Yahia 2012-01-11 08:25:46

回答

5

您應該能夠使用任務是:

//first start a task for each element in s, and add the tasks to the tasks collection 
var tasks = new List<Task>(); 
foreach(var t in s) 
{ 
    tasks.Add(Task.Factory.StartNew(method(t))); 
} 

//then wait for all tasks to complete asyncronously 
Task.WaitAll(tasks); 

//then add the result of all the tasks to r in a treadsafe fashion 
foreach(var task in tasks) 
{ 
    r.Add(task.Result); 
} 

編輯 有一些問題與上面的代碼。有關工作版本,請參閱下面的代碼。在這裏,我還重寫了使用LINQ進行可讀性問題的循環(並且在第一個循環的情況下,爲了避免在lambda表達式內引起問題,在t上關閉)。

var tasks = s.Select(t => Task<int>.Factory.StartNew(() => method(t))).ToArray(); 

//then wait for all tasks to complete asyncronously 
Task.WaitAll(tasks); 

//then add the result of all the tasks to r in a treadsafe fashion 
r = tasks.Select(task => task.Result).ToList(); 
+0

錯誤'System.Threading.Tasks.TaskFactory.StartNew(System.Action)'的最佳重載方法匹配有一些無效參數\t我不斷收到有關tasks.Add(Task.Factory.StartNew(method(t ))); – ikel 2012-01-11 07:48:47

+0

我看到的代碼存在一些問題。給我兩分鐘來爲你編輯它。 – 2012-01-11 08:19:24

+0

ikel - 在那裏,看看我的編輯。代碼清理了一下:) – 2012-01-11 08:24:31

4

您可以使用Parallel.ForEach這將利用多個線程並行執行執行。您必須確保所有調用的代碼都是線程安全的並且可以並行執行。

Parallel.ForEach(s, t => r.add(method(t)); 
+0

這是新東西,以前從未使用過,我會試着回到這裏,非常感謝 – ikel 2012-01-11 06:44:36

+4

這幾乎可以,但這裏的問題是r上的add方法(我期望r是List或類似的)不是線程安全的,並且從多個不同的線程**添加到List將會導致問題。 – 2012-01-11 06:45:35

0

從我看到你正在更新循環內的共享集合。這意味着如果您並行執行循環,則會發生數據競爭,因爲多個線程會同時嘗試更新未同步的集合(假設rList或類似的東西),從而導致不一致的狀態。

並行執行正確,你將需要包裝的代碼段鎖語句中:

object locker = new object(); 
Parallel.Foreach (s, 
    t => 
    { 
     lock(locker) r.add(method(t)); 
    }); 

然而,這將使執行實際串口,因爲每個線程需要獲取鎖,兩個線程不能同時進行。

更好的解決方案是爲每個線程設置一個本地列表,將部分結果添加到該列表中,然後在所有線程完成時合併結果。可能@ØyvindKnobloch-Bråthen的第二個解決方案是最好的,假設method(t)是這種情況下真正的CPU-Hog。

0

修改爲這個問題的正確答案 改變

tasks.Add(Task.Factory.StartNew(method(t);)); 

​​