2017-05-03 57 views
0

我是異步編程的新手。我想在等待任何任務之前啓動一系列任務(發出http請求)。什麼時候Task.WhenAll枚舉?

List<Guid> identifiers; 

//Set identifiers to what they should be 

var task = Task.WhenAll(identifiers.Select(id => _serviceConnector.GetAsync(id))); 

// Call and await another request 

await task; 

我的問題是:我的http請求是否會通過Task.WhenAll創建任務而被啓動?或者等到進一步下去,他們纔會開始?謝謝!

回答

1

通過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,直到完成所有任務並且我們可以獲取結果。

1

WhenAll立即(並同步)將其可枚舉參數。因此,所有任務將在WhenAll返回時開始。

如果您想到這一點,這是有道理的。 WhenAllmust知道它正在等待多少任務,以便知道自己的任務何時完成。此外,它必須鏈接到這些任務中的每一個,以便在每個子任務完成時通知它。沒有其他時間做這項工作;它必須計數並在返回之前設置通知。