澳门在线威尼斯官方 > 澳门在线威尼斯官方 > 异步编程中的最佳做法,上下文问题

原标题:异步编程中的最佳做法,上下文问题

浏览次数:87 时间:2019-12-01

async / await 使异步代码更便于写,因为它隐蔽了数不完细节。 超级多那些细节都捕获在 SynchronizationContext 中,那么些恐怕会变动异步代码的一言一动完全出于你实行你的代码的条件(比方WPF,Winforms,调控台或ASP.NET)所决定。 若果尝试通过忽视 SynchronizationContext 产生的熏陶,您恐怕遇到死锁和竞争原则境况。

初藳链接

SynchronizationContext 调控职务三番五遍的调整方式和地方,况且有过多见仁见智的上下文可用。 若是你正在编写制定二个 WPF 应用程序,创设一个网址或应用 ASP.NET 的API,你应有理解你已经选拔了两个别饶风趣的 SynchronizationContext 。

最近来,涌现了非常多有关 Microsoft .NET Framework 4.5中新添了对 async 和 await 辅助的音讯。 本文意在作为学习异步编制程序的“第二步”;小编借使您已阅读过关于那意气风发端的足足少年老成篇介绍性作品。 本文不提供任何新故事情节,Stack Overflow、MSDN 论坛和 async/await FAQ 那类在线能源提供了相似的提出。 本文只入眼介绍一些溺水在文书档案海洋中的最好做法。

 

正文中的最棒做法更加大程度上是“教导原则”,并不是实在准绳。 在那之中每种引导标准都有局地例外情状。 作者将降解各种辅导典型背后的开始和结果,以便能够理解地问询曾几何时适用以致几时不适用。 图 1 香港中华总商会结了那么些引导原则;笔者就要偏下各节中种种研讨。

SynchronizationContext in a console application

澳门在线威尼斯官方 ,让我们来拜见调控台应用程序中的一些代码:

public class ConsoleApplication
{
    public static void Main()
    {
        Console.WriteLine($"{DateTime.Now.ToString("T")} - Starting");
        var t1 = ExecuteAsync(() => Library.BlockingOperation());
        var t2 = ExecuteAsync(() => Library.BlockingOperation()));
        var t3 = ExecuteAsync(() => Library.BlockingOperation()));

        Task.WaitAll(t1, t2, t3);
        Console.WriteLine($"{DateTime.Now.ToString("T")} - Finished");
        Console.ReadKey();
    }

    private static async Task ExecuteAsync(Action action)
    {
        // Execute the continuation asynchronously
        await Task.Yield();  // The current thread returns immediately to the caller
                             // of this method and the rest of the code in this method
                             // will be executed asynchronously

        action();

        Console.WriteLine($"{DateTime.Now.ToString("T")} - Completed task on thread {Thread.CurrentThread.ManagedThreadId}");
    }
}

在那之中 Library.BlockingOperation(卡塔尔(英语:State of Qatar)是三个第三方库,大家用它来梗塞正在使用的线程。 它能够是任何堵塞操作,不过为了测量检验的目标,您能够行使 Thread.Sleep(2卡塔尔(قطر‎来代表完结。

运作程序,输出结果为:

16:39:15 - Starting

16:39:17 - Completed task ``on thread 11

16:39:17 - Completed task ``on thread 10

16:39:17 - Completed task ``on thread 9

16:39:17 - Finished

在示范中,大家创造八个职分堵塞线程后生可畏段时间。 Task.Yield 强制叁个主意是异步的,通过调节这么些讲话之后的具备剧情(称为_continuation_)来实行,但立即将调控权再次来到给调用者(Task.Yield 是告诉调节者"笔者已管理到位,能够将试行权让给其余的线程",至于最后调用哪个线程,由调节者决定,大概下三个调治的线程依然自个儿自己)。 从输出中得以看看,由于 Task.Yield 全部的操作最后并行奉行,总实践时间唯有两秒。

 

图 1 异步编制程序指点原则计算

SynchronizationContext in an ASP.NET application

假定我们想在 ASP.NET 应用程序中收音和录音这几个代码,我们将代码 Console.WriteLine 调换为 HttpConext.Response.Write 就能够,我们得以看出页面上的输出:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        HttpContext.Response.Write($"{DateTime.Now.ToString("T")} - Starting");
        var t1 = ExecuteAsync(() => Library.BlockingOperation()));
        var t2 = ExecuteAsync(() => Library.BlockingOperation()));
        var t3 = ExecuteAsync(() => Library.BlockingOperation()));

        Task.WaitAll(t1, t2, t3);
        HttpContext.Response.Write($"{DateTime.Now.ToString("T")} - Finished");

        return View();
    }

    private async Task ExecuteAsync(Action action)
    {
        await Task.Yield();

        action();
        HttpContext.Response.Write($"{DateTime.Now.ToString("T")} - Completed task on thread {Thread.CurrentThread.ManagedThreadId}");
    }
}

我们会发觉,在浏览器中运营此页面后不会加载。 看来大家是引进了叁个死锁。那么这里毕竟产生了怎么呢?

死锁的原故是调节台应用程序调节异步操作与 ASP.NET 不相同。 即便调控台应用程序只是调节线程池上的职务,而 ASP.NET 确定保证同大器晚成 HTTP 央浼的具备异步职分都按顺序实践。 由于 Task.Yield 将余下的做事排队,并及时将调控权再次来到给调用者,由此大家在运营Task.WaitAll 的时候有四个等待操作。 Task.WaitAll 是二个不通操作,肖似的围堵操作万幸似 Task.Wait 或 Task.Result,因而阻止当前线程。

ASP.NET 是在线程池上调整它的天职,堵塞线程并不是促成死锁的来由。 不过由于是逐风姿浪漫实践,那形成不一致敬等待操作起来实践。 要是她们不能起动,他们将永世不可能成功,被截留的线程不可能接二连三。

此调节机制由 SynchronizationContext 类控制。 每当大家静观其变义务时,在等候的操作完结后,在 await 语句(即三回九转)之后运营的有所剧情就要日前 SynchronizationContext 上被调解。 上下文决定了怎么着、曾几何时和在哪里推行义务。 您能够采取静态 SynchronizationContext.Current 属性访谈当前上下文,並且该属性的值在 await 语句此前和未来一向相仿。

在调节台应用程序中,SynchronizationContext.Current 始终为空,那代表连接能够由线程池中的任何空闲线程拾取,这是在首先个示范中能并行施行操作的缘故。 不过在我们的 ASP.NET 调整器中有一个AspNetSynchronizationContext,它确认保障后面提到的依次管理。

要点一:

决不接纳窒碍职责同步方法,如 Task.Result,Task.Wait,Task.WaitAll 或 Task.WaitAny。 调整台应用程序的 Main 方法这段时间是该法则唯生机勃勃的不一致(因为当它们获取完全异步时的表现会全部退换)。

 

“名称” 说明 异常
避免 Async Void 最好使用 async Task 方法而不是 async void 方法 事件处理程序
始终使用 Async 不要混合阻塞式代码和异步代码 控制台 main 方法
配置上下文 尽可能使用 ConfigureAwait(false) 需要上下文的方法

本文由澳门在线威尼斯官方发布于澳门在线威尼斯官方,转载请注明出处:异步编程中的最佳做法,上下文问题

关键词:

上一篇:没有了

下一篇:这可能是php世界中最好的日志库