c# – 如何并行执行嵌套的异步/等待代码,同时在等待延续中保持相​​同的线程?

前端之家收集整理的这篇文章主要介绍了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有这个.
>使用自定义TaskScheduler. await查看TaskScheduler.Current并在该调度程序中恢复,如果它是非默认的.

我不确定这两种选择是否有任何利弊.选项2我认为更容易确定范围.选项2看起来像:

Task.Factory.StartNew(
    () => MethodA(),new ConcurrentExclusiveSchedulerPair().ExclusiveScheduler).Unwrap();

对每个并行调用调用一次,并使用Task.WaitAll加入所有这些任务.也许你应该处理那个调度程序.

我(ab)在这里使用ConcurrentExclusiveSchedulerPair来获取单线程调度程序.

如果这些方法不是特别占用cpu方法,则可以对所有这些方法使用相同的调度程序/线程.

猜你在找的C#相关文章