并行运行任务

时间:2016-02-25 22:00:34

标签: c# task-parallel-library task

我无法理解为什么这似乎没有并行运行任务:

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

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

2 个答案:

答案 0 :(得分:4)

如果GetAllRouterInterfacesasync方法,则生成的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并且返回Task,但仍然会发出同步POST请求(可能在任何其他await之前)。这可以解释为什么在获得最小并发性时,因为在发出此请求时,GetAllRouterInterfaces的每次调用都会阻塞。理想的解决方案是发出异步POST请求,例如:

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

这将确保您的for循环不会被阻止,并且请求会同时发生。

会话后进一步更新

似乎你无法使POST请求异步,GetAllRouterInterfaces实际上并没有进行任何异步工作,因此我建议如下:

  1. async移除GetAllRouterInterfaces并将返回类型更改为MyReturnType
  2. 并行调用GetAllRouterInterfaces

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

答案 1 :(得分:1)

我不知道我是否理解你的正确方法。

首先,如果 GetAllRouterInterfaces 返回一个任务,则必须等待结果。

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