在C#理解上下文5异步/ AWAIT(Understanding context in C# 5 a

2019-06-18 04:47发布

难道我纠正异步/ AWAIT本身无关并发/并行性,无非是延续传递风格(CPS)实现的更多? 而真正的线程被执行SynchronizationContext该实例await通行证/恢复?

如果这是正确的我对以下问题SynchronizationContext
它保证的延续将在同一线程上执行。

然而,是否有该线程的上下文信息被永久保存的任何担保? 我的意思是NameCurrentPrincipalCurrentCultureCurrentUICulture等是否依赖于框架(ASP.NET,WinForms的,WCF,WPF)?

Answer 1:

我是正确的是异步/ AWAIT本身无关并发/并行性,无非是CPS实现的更多?

那么, async / await是使用CPS重写,所以你的核心的理解是正确的。

关于“并发”和“并行”,我会说,它确实使并发; 你可以启动多个async同时操作,这些操作都是“飞行”。 这是容易做到Task.WhenAllTask.WhenAny

此外,即使async本身并不意味着“多线程”, Task.Run确实能够轻松async兼容多线程

而真正的线程是由等待通行证/恢复的SynchronizationContext实例执行?

想想这样的方式:由CPS重写创建的延续有什么地方运行。 所捕获的“异步上下文”可被用于调度的延续。

附注:捕捉的情况下实际上是SynchronizationContext.Current 除非它为空 ,在这种情况下拍摄的背景是TaskScheduler.Current

另一个重要的注意事项:捕捉和上下文的恢复实际上是上升到“awaiter”对象。 因此,在默认情况下,如果你await一个Task (或任何其他内置awaitable),上下文将被捕获和恢复。 但是,如果你await的结果ConfigureAwait(false) ,那么上下文没有捕获。 同样,如果您await自己的自定义awaitable,也不会捕捉范围内(除非你对编程)。

然而,是否有该线程的上下文信息被永久保存的任何担保? 我的意思是名称,CurrentPrincipal,的CurrentCulture,的CurrentUICulture,等等。

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

在UI应用,文化不流动,但默认情况下它的所有线程在同一反正。 Name是绝对不会流出,除非你继续在同一个线程(例如,使用UI SynchronizationContext )。


对于一些进一步的阅读,我建议首先是我自己的async / await教程 ,然后正式async / await FAQ 。 然后看看斯蒂芬Toub的博客文章ExecutionContext对比SynchronizationContext

您也可以找到我SynchronizationContext文章很有帮助。



Answer 2:

不, 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();

这approxiamtely转换为

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代码。 但是,您可以设置使用TPL代码的情况下,通过SynchronisationContex关键字。



文章来源: Understanding context in C# 5 async/await