c# – 如何并行执行嵌套的异步/等待代码,同时在等待延续中保持相
这可能是我写过的最糟糕的StackOverflow标题.我实际上要做的是执行一个异步方法,该方法在同步方法中多次并行使用async / await约定(并且本身包含额外的await调用),同时在整个执行每个分支的过程中保持相同的线程.并行执行,包括所有等待延续.换句话说,我想同步执行一些异步代码,但我想多次并行执行.现在你可以看到为什么标题太糟糕了.也许最好用一些代码来说明……
假设我有以下内容: public class MyAsyncCode { async Task MethodA() { // Do some stuff... await MethodB(); // Some other stuff } async Task MethodB() { // Do some stuff... await MethodC(); // Some other stuff } async Task MethodC() { // Do some stuff... } } 调用者是同步的(来自控制台应用程序).让我尝试说明我尝试使用Task.WaitAll(…)和包装器任务时要做的事情: public void MyCallingMethod() { List<Task> tasks = new List<Task>(); for(int c = 0 ; c < 4 ; c++) { MyAsyncCode asyncCode = new MyAsyncCode(); tasks.Add(Task.Run(() => asyncCode.MethodA())); } Task.WaitAll(tasks.ToArray()); } MethodA,MethodB和MethodC的所有行为都是在连续之前和之后在同一个线程上运行,并且在4个不同的线程上并行发生4次.换句话说,我想删除我的await调用的异步行为,因为我正在从调用者并行调用. 现在,在我进一步讨论之前,我确实理解异步代码和并行/多线程代码之间存在差异,前者并不暗示或暗示后者.我也知道实现此行为的最简单方法是删除async / await声明.不幸的是,我没有选择这样做(它在库中)并且有理由为什么我需要所有的延续都在同一个线程上(与所述库的糟糕设计有关).但更重要的是,这引起了我的兴趣,现在我想从学术角度来了解. 我试图使用PLINQ和使用.AsParallel()立即执行任务来运行它.选择(x => x.MethodA().结果).我还试图使用在这里和那里找到的AsyncHelper类,它实际上只使用.Unwrap().GetAwaiter().GetResult().我也试过其他的东西,我似乎无法得到理想的行为.我要么最终得到同一个线程上的所有调用(显然不是并行),要么以不同线程上执行的连续结束. 我正在尝试做什么,甚至是async / await和TPL太不同了(尽管两者都基于任务)? 解决方法
您调用的方法不使用ConfigureAwait(false).这意味着我们可以强制继续在我们喜欢的上下文中恢复.选项:
>安装单线程同步上下文.我相信Nito.Async有这个. 我不确定这两种选择是否有任何利弊.选项2我认为更容易确定范围.选项2看起来像: Task.Factory.StartNew( () => MethodA(),new ConcurrentExclusiveSchedulerPair().ExclusiveScheduler).Unwrap(); 对每个并行调用调用一次,并使用Task.WaitAll加入所有这些任务.也许你应该处理那个调度程序. 我(ab)在这里使用ConcurrentExclusiveSchedulerPair来获取单线程调度程序. 如果这些方法不是特别占用CPU的方法,则可以对所有这些方法使用相同的调度程序/线程. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |