我无法理解为什么这似乎没有并行运行任务:
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);
任务开始。我想将所有新任务添加到列表中,然后并行执行它们。
答案 0 :(得分:4)
如果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);
从评论中更新
似乎尽管GetAllRouterInterfaces
为async
并且返回Task
,但仍然会发出同步POST请求(可能在任何其他await
之前)。这可以解释为什么在获得最小并发性时,因为在发出此请求时,GetAllRouterInterfaces
的每次调用都会阻塞。理想的解决方案是发出异步POST请求,例如:
await webclient.PostAsync(request).ConfigureAwait(false);
这将确保您的for
循环不会被阻止,并且请求会同时发生。
会话后进一步更新
似乎你无法使POST请求异步,GetAllRouterInterfaces
实际上并没有进行任何异步工作,因此我建议如下:
async
移除GetAllRouterInterfaces
并将返回类型更改为MyReturnType
并行调用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);
}
}
));
}