通过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,直到完成所有任务并且我们可以获取结果。