繁体   English   中英

了解C#5 async / await中的上下文

[英]Understanding context in C# 5 async/await

我是否正确async / await本身与并发/并行无关,只不过是继续传递样式(CPS)实现? 真正的线程是由await传递/恢复的SynchronizationContext实例执行的?

如果这是正确的,我有关于SynchronizationContext的以下问题:
它保证在同一个线程上执行延续。

但是,是否有任何保证线程的上下文信息是持久的? 我的意思是NameCurrentPrincipalCurrentCultureCurrentUICulture等。它依赖于框架(ASP.NET,WinForms,WCF,WPF)吗?

我是否正确async / await本身与并发/并行无关,只不过是CPS实现?

好吧, async / await是一个使用CPS的重写,所以你的核心理解是正确的。

关于“并发”和“并行”,我会说它确实能够实现并发性; 你可以同时启动多个async操作,这些操作都在“飞行中”。 使用Task.WhenAllTask.WhenAny很容易做到这一点。

此外,尽管async本身并不意味着“多线程”,但Task.Run确实可以实现简单的async兼容多线程

真正的线程是由等待传递/恢复的SynchronizationContext实例执行的?

可以这样想:CPS重写创建的延续必须在某个地方运行。 捕获的“异步上下文”可用于安排继续。

附注:捕获的上下文实际上是SynchronizationContext.Current 除非它为null ,在这种情况下捕获的上下文是TaskScheduler.Current

另一个重要的注意事项:上下文的捕获和恢复实际上取决于“awaiter”对象。 因此,默认情况下,如果您await Task (或任何其他内置的等待),将捕获并恢复上下文。 但是,如果await ConfigureAwait(false)的结果,则不会捕获上下文。 同样,如果您await自己的自定义等待,它将不会捕获上下文(除非您将其编程)。

但是,是否有任何保证线程的上下文信息是持久的? 我的意思是Name,CurrentPrincipal,CurrentCulture,CurrentUICulture等。

SynchronizationContextExecutionContext不同。 一个简单的答案是ExecutionContext总是“流”,所以CurrentPrincipal流(如果没有,它可能是一个安全问题,这就是为什么不流动ExecutionContext API总是在Unsafe结束)。

在UI应用程序中,文化不会流动,但默认情况下,所有线程都是相同的。 除非您在同一个线程上恢复(例如,使用UI SynchronizationContext ),否则Name肯定不会流动。


为了进一步阅读,我建议从我自己的async / await教程开始 ,然后是官方的async / await FAQ 然后看看Stephen Toub关于ExecutionContextSynchronizationContext的博客文章

您可能还会发现我的SynchronizationContext文章很有帮助。

不, async / await关键字与并发性有关。 async / await基本上将您的方法代码包装到任务和继续中。 要查看编​​译器生成的确切转换(使用任务并行库),请反汇编一些代码段。 async / await用法的这种翻译与下面的例子“相似”(但不完全相同!)

async Task<int> TaskOfTResult_MethodAsync()
{
    int hours;
    // . . .
    // Return statement specifies an integer result.
    return hours;
}

// Calls to TaskOfTResult_MethodAsync
Task<int> returnedTaskTResult = TaskOfTResult_MethodAsync();
int intResult = await returnedTaskTResult;
// or, in a single statement
int intResult = await TaskOfTResult_MethodAsync();

这是近似转换为

private int Result()
{
    int hours;
    // . . .
    // Return statement specifies an integer result.
    return hours;
}

在等待方法之外等待返回的地方

int? hours = null;
Task<int> task = null;
task = Task.Factory.StartNew<int>(() => Result());
task.ContnueWith(cont => 
{
    // Some task completion checking...
    hours = task.Result;
}, CancellationToken.None, 
   TaskCreationOptions.None, 
   TaskScheduler.Current);

或者,您可以将TPL代码放入Result方法中

private int ResultAsync()
{
    int? hours = null;
    Task<int> task = null;
    task = Task.Factory.StartNew<int>(() => 
    {
        int hours;
        // . . .
        // Return statement specifies an integer result.
        return hours;
    }, CancellationToken.None, 
       TaskCreationOptions.None, 
       TaskScheduler.Current);
    try
    {
        return task.Result;
    }
    catch (AggregateException aggEx)
    {
        // Some handler method for the agg exception.
        aggEx.Handle(HandleException); 
    }
}

SynchronizationContext不保证将在async / awate代码的同一线程上执行awate 但是,您可以使用TPL代码通过SynchronisationContex关键字设置上下文。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM