Task.WhenAll何时枚举? [英] When does Task.WhenAll enumerate?

查看:54
本文介绍了Task.WhenAll何时枚举?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是异步编程的新手.我想开始一系列任务(发出http请求),然后再等待它们中的任何一个.

I'm pretty new to async programming. I want to kick off a series of tasks (which make http requests) before awaiting any of them.

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;

我的问题是:通过Task.WhenAll创建任务后,我的http请求是否会启动?还是要等到更久以后才能启动它们?谢谢!

My question is: Will my http requests be kicked off with the createion of the task through Task.WhenAll? Or will they not be started until the await further down? Thanks!

推荐答案

我的http请求将随着任务的创建而启动通过Task.WhenAll吗?还是要等到进一步等待才开始?

Will my http requests be kicked off with the creation of the task through Task.WhenAll? Or will they not be started until the await further down?

当您将 IEnumerable< Task> 传递给 Task.WhenAll 时,它将枚举任务序列并将它们全部列出以进行进一步处理:

When you pass IEnumerable<Task> to Task.WhenAll it enumerates the sequence of tasks and puts them all to list for further processing:

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查询,它将被执行:

that means if you pass a LINQ query, it will be executed:

identifiers.Select(id => _serviceConnector.GetAsync(id))

但这并不意味着 Task.WhenAll 启动这些任务.例如.如果查询将返回尚未启动的任务,则这些任务将保持未运行状态.例如.以下查询将创建任务,但不会启动它们,因此 WhenAll 将停留在等待这些任务的过程中

but it does not mean that Task.WhenAll starts those tasks. E.g. if your query will return tasks which have not been started, then those tasks will stay in non-running state. E.g. following query will create tasks but will not start them, thus WhenAll will stuck waiting for these tasks

var tasks = Enumerable.Range(1, 10).Select(i => new Task<int>(() => i));
var task = Task.WhenAll(tasks);

在您的情况下,一切都取决于 GetAsync(id)方法.如果它创建并启动任务(如 HttpClient 一样),则将创建所有任务并在 Task.WhenAll 调用的开始处启动.

In your case everything depends on GetAsync(id) method. If it creates and starts a task (like HttpClient does) then all tasks would be created and started at the beginning of Task.WhenAll call.

TL; DR WhenAllPromise< T>

private sealed class WhenAllPromise<T> : Task<T[]>, ITaskCompletionAction

如您所见,此任务实现了 ITaskCompletionAction .这是一个内部接口,用于向任务添加完成操作-连续任务的轻量级版本(因为这是一个简单的操作).此接口定义单个方法 Invoke(Task),当任务完成执行时应调用该方法. Task 有一个内部方法,可以添加以下轻量级的延续:

As you can see this task implements ITaskCompletionAction. This is an internal interface, which is used to add completion action to tasks - the lightweight version of continuation tasks (because it's a simple action). This interface defines single method Invoke(Task) which should be invoked when task completes execution. Task has an internal method which allows adding these lightweight continuations:

internal void AddCompletionAction(ITaskCompletionAction action)

现在返回到 WhenAllPromise< T> 类.它有两个字段:

Now back to WhenAllPromise<T> class. It has two fields:

private readonly Task<T>[] m_tasks;
private int m_count;

在初始化期间,此类将所有给定任务存储在字段数组中,初始化计数器,并为已完成的任务调用继续操作,或者将其自身添加到任务完成操作中:

During initialization this class stores all given tasks in field array, initializes counter, and either invokes continuation for already completed tasks or adds itself to task completion actions:

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,直到所有任务都完成并且我们可以抓取结果为止.

That's it. Tasks are not started by WhenAllPromise class. It only uses callback action which is invoked when tasks are completed. In callback action it decreases m_count each time some of tasks is completed, until all tasks are done and we can grab results.

这篇关于Task.WhenAll何时枚举?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆