简体   繁体   English

并行运行任务

[英]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实际上并没有执行任何异步工作,因此,我建议以下建议:

  1. Remove async from GetAllRouterInterfaces and change the return type to MyReturnType GetAllRouterInterfaces删除async并将返回类型更改为MyReturnType
  2. 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM