运行 并行任务

Running 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());

通过单步执行,我看到这一行一被评估:

tasks[i] = CAS.Service.GetAllRouterInterfaces(mbis[i], 3);

任务开始。我想将所有新任务添加到列表中,然后并行执行它们。

如果 GetAllRouterInterfaces 是一个 async 方法,则生成的 Task 将已经启动(请参阅 this answer 了解更多说明)。

这意味着 tasks 将包含多个任务,所有这些任务都是 运行 并行的,而无需随后调用 Parallel.ForEach

您可能希望等待 tasks 中的所有条目完成,您可以使用 await Task.WhenAll(tasks);

所以你最终应该得到:

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);

根据评论更新

似乎尽管 GetAllRouterInterfacesasync 并且 return 正在 Task 它仍在发出同步 POST 请求(大概在任何其他 await).这可以解释为什么在发出此请求时每次调用 GetAllRouterInterfaces 都会阻塞,因此并发性最小。理想的解决方案是发出异步 POST 请求,例如:

await webclient.PostAsync(request).ConfigureAwait(false);

这将确保您的 for 循环不被阻塞并且请求是并发的。

对话后进一步更新

您似乎无法使 POST 请求异步并且 GetAllRouterInterfaces 实际上不执行任何异步工作,因此我建议如下:

  1. GetAllRouterInterfaces 中删除 async 并将 return 类型更改为 MyReturnType
  2. 像这样并行调用GetAllRouterInterfaces

    var routerInterfaces = mbis.AsParallel()
        .Select(mbi => CAS.Service.GetAllRouterInterfaces(mbi, 3));
    

不知道我理解的对不对。

首先,如果 GetAllRouterInterfaces 是 returns 任务,您必须等待结果。

使用 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);
                }
        }
       ));
}