等待很多任务

Max*_*Max 4 c# multithreading asynchronous async-await c#-5.0

我有一组Task(很多,大约400):

IEnumerable<Task> tasks = ...
Run Code Online (Sandbox Code Playgroud)

我想同时运行它们然后等待它们中的每一个.我使用这段代码来运行任务:

Task.Run(async () => { ... });
Run Code Online (Sandbox Code Playgroud)

每个任务都会自己运行异步方法,这就是我需要asynclambda中的关键字的原因.在这些嵌套任务中,众所周知HTTP地发送了请求以及HTTP接收到的响应.

我尝试了两种不同的方法来等待所有任务完成:

await Task.WhenAll(tasks);
Run Code Online (Sandbox Code Playgroud)

foreach (var task in tasks)
{
    await task;
}
Run Code Online (Sandbox Code Playgroud)

哪个,先验,对我来说看起来完全一样(但当然它们似乎不是我不会在这里首先发布的......).

第一种方法使任务运行得更快,但A first chance exception of type 'System.Net.Sockets.SocketException' occurred in System.dll在输出窗口中有大量的和其他类似的东西.而且,有些任务在调用之后仍然处于WaitingForActivation状态.await Task.WhenAll()

第二种方式是较慢的,看起来任务没有同时运行(我HTTP逐个接收响应,而第一种等待任务的方式使它们几乎同时出现).此外,first chance exception当我使用foreach循环等待每个任务并且WaitingForActivation循环之后没有任务具有状态时,我在输出窗口中看不到任何输入.

我理解等待一组任务的"最佳"方法是使用WhenAll()(至少为了可读性),但为什么这两种方法表现不同?我怎样才能克服这个问题?理想情况下,我希望任务快速运行并确保一切都结束(我try catch finally在lambda中有一个块来处理服务器错误,我没有忘记if(httpClient != null) httpClient.Dispose()finally之前有人问过......).

任何提示都是受欢迎的!

编辑:

好的,我尝试了另一件事.我补充说:

.ContinueWith(x => System.Diagnostics.Debug.WriteLine("#### ENDED = " + index)));
Run Code Online (Sandbox Code Playgroud)

对每个任务来说,index都是数量Task.使用foreach循环时,我得到:

#### ENDED = 0
#### ENDED = 1
#### ENDED = 2
#### ENDED = 3
#### ENDED = 4
...
Run Code Online (Sandbox Code Playgroud)

使用时WhenAll(),我得到:

#### ENDED = 1
#### ENDED = 3
#### ENDED = 0
#### ENDED = 4
#### ENDED = 8
...
Run Code Online (Sandbox Code Playgroud)

所以使用foreach循环使我的所有任务同步运行......这也许可以解释为什么我First Chance Exception在输出窗口中没有得到任何东西,因为系统根本没有被算法强调.

EDIT2:

示例代码:http://pastebin.com/5bMWicD4

它使用了这里提供的公共服务:http://timezonedb.com/

Pan*_*vos 5

这两次尝试完全不同.

第一次尝试等待所有任务完成并在之后继续.只有在完成所有任务后才会抛出.结果的顺序是不确定的,并且取决于首先完成哪个任务.

第二个按照它们放在任务数组中的顺序逐个等待每个任务,这当然不是你想要的,而且速度很慢.如果一个任务失败,它将中止等待异常.其他任务的结果将丢失.

它并不完全像是同步运行任务,因为某些任务会比其他任务更早完成,但您仍然需要一次检查所有任务.

你应该注意这里Task.WhenAll不会自行阻止.它返回一个任务,在所有其他任务完成后完成.通过呼叫await Task.WhenAll你等待该任务的完成.您可以检查该任务的状态以查看一个或多个子任务是否失败或被取消,或者通过调用ContinueWith来处理结果.

您也可以调用Task.WaitAll而不是await Task.WhenAll阻止,直到所有任务完成,或者至少其中一个任务取消或中止.这有点类似于你的第二次尝试,尽管它仍然避免一个接一个地等待所有任务.

你有很多例外的事实与你等待的方式无关.您可以一次向同一个域(即地址)建立多少HTTP连接,可能存在超时错误(通常由连接限制引起)或其他与网络相关的问题.

但是,您收到的例外情况会受到您是否致电await Task.WhenAllTask.WaitAll.这篇文章解释了这个问题,但简而言之,Task.WaitAll将收集所有异常并抛出AggregateException,同时await Task.WhenAll只返回其中一个异常.

顺便说一句,你收到的SocketException消息是什么?