paralell.foreach中的嵌套异步方法

问题描述 投票:1回答:2

我有一个在其中运行多个异步方法的方法。我必须遍历设备列表,然后将设备传递给此方法。我注意到这需要很长时间才能完成,因此我正在考虑使用并行foreach,以便它可以同时针对多个设备运行此过程。

假设这是我的方法。

public async Task ProcessDevice(Device device) {
 var dev = await _deviceService.LookupDeviceIndbAsNoTracking(device);

 var result = await DoSomething(dev);
 await DoSomething2(dev);
}

然后,DoSomething2也调用异步方法。

public async Task DoSomething2(Device dev) {
 foreach(var obj in dev.Objects) {
  await DoSomething3(obj);
 }
}

设备列表随着时间的推移不断变大,因此此列表增长的越多,程序完成对每个设备运行ProcessDevice()所花费的时间就越长。我想一次处理多个设备。因此,我一直在研究使用Parallel.Foreach。

Parallel.ForEach(devices, async device => {
 try {
  await ProcessDevice(device);
 } catch (Exception ex) {
  throw ex;
 }
})

似乎在设备被完全处理之前程序已完成。我也尝试过创建任务列表,然后为每个设备添加一个运行ProcessDevice的新任务到该列表中,然后等待Task.WhenAll(listOfTasks);。

var listOfTasks = new List<Task>();
foreach(var device in devices) {
 await Task.Run(async () => await ProcessDevice(device));
listOfTasks.Add(task);
}
await Task.WhenAll(listOfTasks);

但是似乎在ProcessDevice()实际完成运行之前,该任务被标记为已完成。

[请原谅我对此问题的无知,因为我是并行处理的新手,不确定会发生什么情况。是什么引起了这种现象,您是否可以提供任何文档来帮助我更好地理解该怎么做?

c# parallel-processing async-await task-parallel-library parallel.foreach
2个回答
0
投票

在您的上一个示例中,存在一些问题:

var listOfTasks = new List<Task>();
foreach (var device in devices)
{
    await  Task.Run(async () => await ProcessDevice(device));
}
await Task.WhenAll(listOfTasks);

正在执行await Task.Run(async () => await ProcessDevice(device));意味着直到上一个循环完成之前,您将不移至foreach循环的下一个迭代。从本质上讲,您仍然一次只执行一次。

另外,您没有向listOfTasks添加任何任务,因此它保持为空,因此Task.WhenAll(listOfTasks)立即完成,因为没有等待的任务。

尝试一下:

var listOfTasks = new List<Task>();
foreach (var device in devices)
{
    var task = Task.Run(async () => await ProcessDevice(device))
    listOfTasks.Add(task);
}
await Task.WhenAll(listOfTasks);

0
投票

如果您要的话不是很确定,但是我可以举一个我们如何开始异步过程的例子

 private readonly Func<Worker> _worker;

    private void StartWorkers(IEnumerable<Props> props){
    Parallel.ForEach(props, timestamp => { _worker.Invoke().Consume(timestamp); });
    }

建议阅读有关Parallel.ForEach的内容,因为它会对您有所帮助。


0
投票

您无法将asyncParallel.ForEach混合。由于基础操作是异步的,因此您需要使用异步并发,而不是并行性。异步并发最容易用WhenAll表示:

var listOfTasks = devices.Select(ProcessDevice).ToList();
await Task.WhenAll(listOfTasks);
© www.soinside.com 2019 - 2024. All rights reserved.