通過Task.WhenAll創建任務 會啓動我的http請求嗎?或者等到進一步下去,他們纔會開始?
當你傳遞IEnumerable<Task>
到Task.WhenAll
它列舉了一系列任務,並把它們全部列出作進一步處理:
if (tasks == null) throw new ArgumentNullException("tasks");
List<Task<TResult>> taskList = new List<Task<TResult>>();
foreach (Task<TResult> task in tasks)
{
if (task == null) throw new ArgumentException("tasks");
taskList.Add(task);
}
,這意味着如果你傳遞一個LINQ查詢,它將被執行:
identifiers.Select(id => _serviceConnector.GetAsync(id))
,但它並不意味着Task.WhenAll
開始這些任務。例如。如果您的查詢將返回尚未啓動的任務,那麼這些任務將保持非運行狀態。例如。下面的查詢將創建任務,但不會啓動它們,從而將WhenAll
卡住等待這些任務
var tasks = Enumerable.Range(1, 10).Select(i => new Task<int>(() => i));
var task = Task.WhenAll(tasks);
在你的情況下,一切取決於GetAsync(id)
方法。如果它創建了並開始任務(如HttpClient
那樣),則將在Task.WhenAll
調用的開始處創建並開始所有任務。
TL; DR Task.WhenAll
方法的實施細節。如上所述,它抓住都給任務(IEnumerable的說法它把所有任務列表進入),並創建了一個類型WhenAllPromise<T>
private sealed class WhenAllPromise<T> : Task<T[]>, ITaskCompletionAction
的新任務,因爲你可以看到這個任務實現ITaskCompletionAction
。這是一個內部接口,用於向任務添加完成操作 - 繼續任務的輕量級版本(因爲這是一個簡單的操作)。該接口定義了任務完成執行時應調用的單一方法Invoke(Task)
。Task
具有內部方法,它允許將這些輕質延續:
internal void AddCompletionAction(ITaskCompletionAction action)
現在回到WhenAllPromise<T>
類。它有兩個字段:
private readonly Task<T>[] m_tasks;
private int m_count;
在初始化這個類存儲在現場陣列中所有給定的任務,初始化計數器,要麼調用繼續對已經完成的任務或將自身添加到任務完成操作:
m_tasks = tasks;
m_count = tasks.Length;
foreach (var task in tasks)
{
if (task.IsCompleted) this.Invoke(task); // short-circuit
else task.AddCompletionAction(this); // simple completion action
}
而已。任務不是由WhenAllPromise
類啓動的。它只使用在任務完成時調用的回調動作。在回調操作中,每次完成一些任務時,它會減少m_count,直到完成所有任務並且我們可以獲取結果。