dav*_*ick 7 c# parallel-processing multithreading asynchronous async-await
这可能是我写过的最糟糕的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...
}
}
Run Code Online (Sandbox Code Playgroud)
调用者是同步的(来自控制台应用程序).让我尝试说明我尝试使用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());
}
Run Code Online (Sandbox Code Playgroud)
在延续之前和之后MethodA,期望的行为是MethodB,和,并且MethodC都在同一个线程上运行,并且在4个不同的线程上并行发生4次.换句话说,我想删除我的await调用的异步行为,因为我正在从调用者并行调用.
现在,在我进一步讨论之前,我确实理解异步代码和并行/多线程代码之间存在差异,前者并不暗示或暗示后者.我也知道实现此行为的最简单方法是删除async/await声明.不幸的是,我没有选择这样做(它在库中)并且有理由为什么我需要延续所有在同一个线程上(与所述库的不良设计有关).但更重要的是,这引起了我的兴趣,现在我想从学术角度来了解.
我试图使用PLINQ和立即执行任务来运行它.AsParallel().Select(x => x.MethodA().Result).我也试图使用AsyncHelper这里和那里找到的类,它真正使用.Unwrap().GetAwaiter().GetResult().我也试过其他一些东西,我似乎无法得到理想的行为.我要么最终得到同一个线程上的所有调用(显然不是并行),要么以不同线程上执行的连续结束.
我正在尝试做什么,甚至是async/await和TPL太不同了(尽管两者都基于Tasks)?
您调用的方法不使用ConfigureAwait(false). 这意味着我们可以强制延续在我们喜欢的上下文中恢复。选项:
TaskScheduler. await查看TaskScheduler.Current并恢复该调度程序(如果它不是默认的)。我不确定这两种选择是否有任何优点和缺点。我认为选项 2 的范围更容易确定。选项 2 看起来像:
Task.Factory.StartNew(
() => MethodA()
, new ConcurrentExclusiveSchedulerPair().ExclusiveScheduler).Unwrap();
Run Code Online (Sandbox Code Playgroud)
对于每个并行调用调用一次并用于Task.WaitAll连接所有这些任务。也许您也应该处理该调度程序。
我(ab)使用ConcurrentExclusiveSchedulerPair这里来获取单线程调度程序。
如果这些方法不是特别占用 CPU 资源,您可以对所有这些方法使用相同的调度程序/线程。
| 归档时间: |
|
| 查看次数: |
1090 次 |
| 最近记录: |