Parallel.ForEach 中的嵌套异步方法

Jar*_*son 1 c# parallel-processing task-parallel-library async-await parallel.foreach

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

假设这是我的方法。

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

    var result = await DoSomething(dev);
    await DoSomething2(dev);
}
Run Code Online (Sandbox Code Playgroud)

然后 DoSomething2 也调用了一个异步方法。

public async Task DoSomething2(Device dev) {
    foreach(var obj in dev.Objects) {
        await DoSomething3(obj);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

程序似乎在设备完全处理之前完成。我还尝试创建一个任务列表,然后为每个设备添加一个运行 ProcessDevice 的新任务到该列表,然后等待 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);
Run Code Online (Sandbox Code Playgroud)

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

请原谅我对这个问题的无知,因为我是并行处理的新手并且不确定发生了什么。是什么导致了这种行为,您是否可以提供任何可以帮助我更好地了解该怎么做的文档?

Ste*_*ary 7

你不能asyncParallel.ForEach. 由于您的底层操作是异步的,您希望使用异步并发,而不是并行。异步并发最容易表达为WhenAll

var listOfTasks = devices.Select(ProcessDevice).ToList();
await Task.WhenAll(listOfTasks);
Run Code Online (Sandbox Code Playgroud)

  • @Thibaut 一般来说。我刚刚写了一个答案来更详细地解释原因。 (2认同)