[我试图找到处理项目并发处理的最佳方法,该项目由需要顺序执行的各个子任务组成(C#/ .net 4.6)
即同时处理列表中的对象,但是按顺序执行一系列(等待异步)子任务-并且仅在所有操作完成后才运行代码。
伪代码:
public async Task SynchronizeItems() { List<Items> items = await client.RetrieveItems(); foreach (var item in collection) // but in parallel { await item.DoThingA() await item.DoThingB() await item.DoThingC() } // **only run code here when all sub tasks for all items are complete** }
更大的上下文(以简化形式):我有一个可执行文件,需要每N分钟作为计划任务运行。 Program的入口点/ Main方法将初始化ItemSyncService并调用SynchronizeItems()。因为SynchronizeItems()是异步的,所以当控件返回到Main方法时,遇到第一次等待时,整个过程将立即退出。
(仅添加调用SynchronizeItems()。Wait()不起作用,因为这是一种简化的情况。实际上,调用层次结构确实很复杂,其中程序集是动态加载的,调用的方法等,等等)] >
为了防止这种情况(基于我在Stack Overflow上看到的帖子,我添加了ManualResetEvent,以便可以手动控制“所有任务完成”的时间。
static void Main(string[] args) { ManualResetEvent completionEvent = new ManualResetEvent(false); _executor = new ItemService(); _executor.SynchronizeItems(completionEvent) // wait for completion events to be set before exiting the method completionEvent.WaitOne() }
然后,同步方法如下所示:
public async Task SynchronizeItems(ManualResetEvent completionEvent) { List<Items> items = await client.RetrieveItems(); foreach (var item in collection) // but in parallel { await item.DoThingA() await item.DoThingB() await item.DoThingC() } // ** only run code here when all sub tasks for all items are complete** // signal completion completionEvent.Set() }
更改此项以将并行ForEach用于项目级并发看起来像这样:
public async Task SynchronizeItems(ManualResetEvent completionEvent) { List<Items> items = await client.RetrieveItems(); Parallel.ForEach(items, async (item) => // in parallel now { await item.DoThingA() await item.DoThingB() await item.DoThingC() } **// only run code here when all sub tasks for all items are complete ** // signal completion completionEvent.Set() // ** this now runs immediately without waiting ** }
但是,完成此操作后,将为每个项目启动任务后立即调用completionEvent。
我发现了一个实现ParallelForEachAsync(https://github.com/Dasync/AsyncEnumerable)的第三方库。看来这将阻止在所有项目的所有等待任务完成之前设置完成事件。
但是我想知道我是否会错误地进行此操作?最初,当我写这篇文章时,我是作为控制台应用程序进行测试的,并且在交互模式下具有ReadKey(),因此我没有遇到与异步相关的进程退出问题。
[我试图找到处理项目并发处理的最佳方法,该项目由需要依次执行的各个子任务组成(C#/ .net 4.6),即...中的处理对象,
如果DoThings
方法正在发出I / O请求而不是CPU绑定操作,则可以将项目处理移至其自己的方法:
private async Task ProcessItem(Items item) {
await item.DoThingA();
await item.DoThingB();
await item.DoThingC();
}