2017-01-16 62 views
2

難道不可以將任務添加到Task.WhenAll已在等待的列表中嗎?如何將任務添加到Task.WhenAll正在等待的集合中?

我想等待所有任務完成,並且有可能在初始化後創建新的任務。但是這裏Task.WhenAll不會等待稍後添加到集合中的新任務。

List<Task> tasks = new List<Task>(); 

var task1 = Task.Run(async() => 
    { 
     Debug.WriteLine("task #1 started"); 
     await Task.Delay(TimeSpan.FromSeconds(20)); 
     Debug.WriteLine("task #1 finished"); 
    }); 

var task2 = Task.Run(async() => 
{ 
    Debug.WriteLine("task #2 started"); 
    await Task.Delay(TimeSpan.FromSeconds(30)); 
    Debug.WriteLine("task #2 finished"); 
}); 

var task3 = Task.Run(async() => 
{ 
    Debug.WriteLine("task #3 started"); 
    await Task.Delay(TimeSpan.FromSeconds(10)); 
    var inner = Task.Run(async() => 
    { 
     Debug.WriteLine("inner task started"); 
     await Task.Delay(TimeSpan.FromSeconds(40)); 
     Debug.WriteLine("inner task finished"); 
    }); 

    tasks.Add(inner); 

    Debug.WriteLine("task #3 finished"); 
}); 

tasks.Add(task1); 
tasks.Add(task2); 
tasks.Add(task3); 

await Task.WhenAll(tasks); 
Debug.WriteLine("All finished"); 

輸出:

task #2 started 
task #3 started 
task #1 started 
task #3 finished 
inner task started 
task #1 finished 
task #2 finished 
All finished 
inner task finished < didn't wait for this to finish 
+0

如果你看看[源代碼](https://referencesource.microsoft.com/#mscorlib/system/threading/Tasks/Task.cs,69351c6da968e5d1),你會看到集合/數組之前被複制過內部機制踢了進來,因此對原始集合的任何更改都不會被觀察到。 –

+0

我認爲你能做的最好的是手動循環--' while(tasks.Count> 0){等待Task.WhenAll(任務); tasks = tasks.Where(t =>!t.IsCompleted); }'作爲草圖 –

+0

@Damien_The_Unbeliever非常感謝。我認爲這是最好的解決方案。你不會把它寫成答案嗎? – Blendester

回答

1

Task.WhenAll總是copies它實際上開始等待的前向任務引用。這意味着可以在等待過程中更新原始集合,但WhenAll完全忽略了這些更改。

我建議,而是在一個循環中運行WhenAll。沿着線的東西:

while(tasks.Count > 0) { 
    await Task.WhenAll(tasks); 
    tasks = tasks.Where(t => !t.IsCompleted); 
} 

(隨着你是否希望具體細節離開tasks本身未修改,確切的正確的數據類型是什麼變量,等等,留給由讀者填寫演習)

5

這是因爲tasks.Add(inner)await Task.WhenAll(tasks)後執行。要回答您的問題,首先您需要清除任務#3任務內部之間的關聯。 IMO的內在任務應該是任務#3的一部分。也就是說,任務#3無法完成,直到內部任務完成。

await inner; //instead of tasks.Add(inner); 
+0

謝謝。但那是爲了示範。新任務可以從任何地方添加到「任務」。我的問題是,當方法到達結束時,我想要完成所有任務。也許我正在解決一個錯誤的問題 – Blendester