[英]Running Tasks in parallel
I am failing to understand why this doesn't seem to run the tasks in Parallel: 我无法理解为什么这似乎不能并行运行任务:
var tasks = new Task<MyReturnType>[mbis.Length];
for (int i = 0; i < tasks.Length; i++)
{
tasks[i] = CAS.Service.GetAllRouterInterfaces(mbis[i], 3);
}
Parallel.ForEach(tasks, task => task.Start());
By stepping through the execution, I see that as soon as this line is evaluated: 通过逐步执行,我看到这一行被评估:
tasks[i] = CAS.Service.GetAllRouterInterfaces(mbis[i], 3);
The task starts. 任务开始。 I want to add all the new tasks to the list, and then execute them in parallel. 我想将所有新任务添加到列表中,然后并行执行它们。
If GetAllRouterInterfaces
is an async
method, the resulting Task
will already be started (see this answer for further explanation). 如果GetAllRouterInterfaces
是一个async
方法,则结果Task
已经启动(请参阅此答案以获取更多说明)。
This means that tasks
will contain multiple tasks all of which are running in parallel without the subsequent call to Parallel.ForEach
. 这意味着tasks
将包含多个任务,所有这些任务并行运行,而无需随后调用Parallel.ForEach
。
You may wish to wait for all the entries in tasks
to complete, you can do this with an await Task.WhenAll(tasks);
您可能希望等待tasks
所有条目完成,可以使用await Task.WhenAll(tasks);
来完成此操作await Task.WhenAll(tasks);
. 。
So you should end up with: 因此,您应该以:
var tasks = new Task<MyReturnType>[mbis.Length];
for (int i = 0; i < tasks.Length; i++)
{
tasks[i] = CAS.Service.GetAllRouterInterfaces(mbis[i], 3);
}
await Task.WhenAll(tasks);
Update from comments 来自评论的更新
It seems that despite GetAllRouterInterfaces
being async
and returning a Task
it is still making synchronous POST requests (presumably before any other await
). 看来,尽管GetAllRouterInterfaces
处于async
并返回Task
但它仍在发出同步POST请求(大概在其他任何await
之前)。 This would explain why you are getting minimal concurrency as each call to GetAllRouterInterfaces
is blocking while this request is made. 这可以解释为什么在进行此请求时,每次对GetAllRouterInterfaces
调用都GetAllRouterInterfaces
阻塞状态,因此您获得的并发度最低。 The ideal solution would be to make an aynchronous POST request, eg: 理想的解决方案是发出一个异步POST请求,例如:
await webclient.PostAsync(request).ConfigureAwait(false);
This will ensure your for
loop is not blocked and the requests are made concurrently. 这将确保您的for
循环不会被阻塞,并且请求是同时进行的。
Further update after conversation 对话后进一步更新
It seems you are unable to make the POST requests asynchronous and GetAllRouterInterfaces
does not actually do any asynchronous work, due to this I have advised the following: 看来您无法使POST请求成为异步请求,并且GetAllRouterInterfaces
实际上并没有执行任何异步工作,因此,我建议以下建议:
async
from GetAllRouterInterfaces
and change the return type to MyReturnType
从GetAllRouterInterfaces
删除async
并将返回类型更改为MyReturnType
Call GetAllRouterInterfaces
in parallel like so 像这样并行调用GetAllRouterInterfaces
var routerInterfaces = mbis.AsParallel() .Select(mbi => CAS.Service.GetAllRouterInterfaces(mbi, 3));
I don't know if I understand you the right way. 我不知道我是否以正确的方式理解您。
First of all, if GetAllRouterInterfaces is returns a Task you have to await the result. 首先,如果GetAllRouterInterfaces返回一个Task,则必须等待结果。
With Parallel.ForEach you can't await tasks like as it is, but you can do something similar like this: 使用Parallel.ForEach,您无法按原样等待任务,但是可以执行类似的操作:
public async Task RunInParallel(IEnumerable<TWhatEver> mbisItems)
{
//mbisItems == your parameter that you want to pass to GetAllRouterInterfaces
//degree of cucurrency
var concurrentTasks = 3;
//Parallel.Foreach does internally something like this:
await Task.WhenAll(
from partition in Partitioner.Create(mbisItems).GetPartitions(concurrentTasks)
select Task.Run(async delegate
{
using (partition)
while (partition.MoveNext())
{
var currentMbis = partition.Current;
var yourResult = await GetAllRouterInterfaces(currentMbis,3);
}
}
));
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.