使用.NET任務並行庫,是否有內置的方式來等待所有正在運行的任務完成,而沒有實際參考任務?是否有可能等待未知的任務完成?
Task.WaitAny()
和Task.WaitAll()
都需要一個Task
實例的數組。我想要的是類似於Task.WaitAll()
的東西,它不接受任何參數,只是等待我的應用程序產生的任何和所有任務完成。
如果沒有,我會在我的框架中構建一些東西,但如果我能幫到的話,我不想重新發明輪子。
使用.NET任務並行庫,是否有內置的方式來等待所有正在運行的任務完成,而沒有實際參考任務?是否有可能等待未知的任務完成?
Task.WaitAny()
和Task.WaitAll()
都需要一個Task
實例的數組。我想要的是類似於Task.WaitAll()
的東西,它不接受任何參數,只是等待我的應用程序產生的任何和所有任務完成。
如果沒有,我會在我的框架中構建一些東西,但如果我能幫到的話,我不想重新發明輪子。
因爲任何.NET代碼都可以產生任何Task
(即BCL,某些圖書館等),您可能不希望等待所有未完成的任務,而只是您自己的代碼創建的那些任務。最簡單的方法是創建自己的工廠,使用的底層一個跟蹤所有未完成的任務,並暴露出所需的等待函數
public class MyTaskFactory {
private HashSet<Task> _tasks = new HashSet<Task>();
public Task<T> StartNew<T>(Func<T> func) {
var t = Task.Factory.StartNew(func);
t.ContinueWith(x => {
lock(_tasks) {
_tasks.Remove(x);
}
});
lock(_tasks) {
_tasks.Add(t);
}
return t;
}
// ... implement other StartNew overrides ...
public void WaitAll() {
Task[] tasks;
lock(_tasks) {
tasks = _tasks.ToArray();
}
Task.WaitAll(tasks);
}
}
我做了一些與此類似的事情,但我允許我的類保持自己的任務列表,並實現您編寫的同一個WaitAll()方法,該方法由IUsesTasks接口公開。這符合我目前的框架。但是,我也喜歡你的想法,可能比我的想法更多。 +1。 –
我接受了這個,因爲我最終做了類似的事情,而且我喜歡't.ContinueWith(x => _tasks.Remove(x));',我沒有想到。謝謝。 –
此代碼不是線程安全的。例如,如果'StartNew'被並行任務調用,可能會嘗試對不是線程安全的容器並行調用'Remove'或'Add'。另外,如果任務在調用WaitAll期間結束,可以同時將'Remove'調用到'ToArray'。這些問題可以通過鎖定或使用線程安全的集合而不是HashSet來解決,但也存在更多細微的問題:例如,如果您當前正在等待的其中一項任務調用「StartNew」,那麼您會有一個「泄漏」的任務。 –
我知道這並不直接回答你的問題,但你可以改變你的架構,因此所有的任務都是作爲一個「主要」任務的子節點創建的。等待這個「主要」任務將自動等待所有的孩子。
您可以創建一個子任務是這樣的:
Task.Factory.StartNew(
() => /* ... */,
TaskCreationOptions.AttachedToParent
);
您可能會發現下面的鏈接有用的,當它涉及到的子任務的題目是:
這是一個整潔的想法 - 我會考慮它。謝謝。 +1 –
通過「所有正在運行的任務,」做你的意思是你在你的進程/應用程序創建的任務? – n8wrl
@ n8wrl:我說過「我的應用程序產生的任何和所有任務」......所以是的。 –