假设我有以下内容:
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太不同了(尽管两者都基于任务)?
解决方法
>安装单线程同步上下文.我相信Nito.Async有这个.
>使用自定义TaskScheduler. await查看TaskScheduler.Current并在该调度程序中恢复,如果它是非默认的.
我不确定这两种选择是否有任何利弊.选项2我认为更容易确定范围.选项2看起来像:
Task.Factory.StartNew( () => MethodA(),new ConcurrentExclusiveSchedulerPair().ExclusiveScheduler).Unwrap();
对每个并行调用调用一次,并使用Task.WaitAll加入所有这些任务.也许你应该处理那个调度程序.
我(ab)在这里使用ConcurrentExclusiveSchedulerPair来获取单线程调度程序.
如果这些方法不是特别占用CPU的方法,则可以对所有这些方法使用相同的调度程序/线程.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。