首页 > 其他 > 详细

为什么避免使用Task.Wait或者Task.Result

时间:2020-12-04 09:06:11      阅读:105      评论:0      收藏:0      [点我收藏+]

目标

  • 简单理解为什么不推荐在调用异步方法时,避免使用Task.Wait,或者Task.Result

示例


private void button1_Click(object sender, EventArgs e)
{
    textBox1.Text = "button1_Click";

    DoSomethingAsync().Wait();

    textBox1.Text = "button1_Click end";
}

public async Task DoSomethingAsync()
{
    await Task.Delay(1000);
    MessageBox.Show("DoSomethingAsyncEnd");
}

private void button2_Click(object sender, EventArgs e)
{
    textBox1.Text = "button2_Click";

    DoSomethingAsync().ConfigureAwait(false);

    textBox1.Text = "button2_Click end";
}


首先我们看上面的button1_Click代码,这种再工作中经常会碰到同事在Web应用中会写这种代码。这种代码在UI程序中会产生上面后果呢?答案是死锁,如下:

技术分享图片

第一步我们先点击了button2可以看到并无什么异常,后面会解释,先让我们看第二步,为什么会程序卡死。button1_Click()(同步)等待DoSomethingAsync()完成,同时阻塞了同步上下文(ui主线程),当Task.Delay语句结束时(这里的结束指,遇到await立即返回调用方后),await试图在已经捕获的上下文(ui主线程,遇到await捕捉)中继续运行DoSomethingAsync()的 MessageBox.Show("DoSomethingAsyncEnd"); 但是此时上下文正在等待DoSomethingAsync()完成,此时就会互相等待(这波,这波是我等我自己)加上ui和Asp.Net上下文每次只能执行一个线程,所以就会死锁。

但是在控制台为什么不会死锁呢?如下:


static void Main(string[] args)
{
    // null
    var syncContext = SynchronizationContext.Current;
    var taskSchedulerContext = TaskScheduler.Current;
    DoSomethingAsync().Wait();

}
public static async Task DoSomethingAsync()
{
    await Task.Delay(1000);
    Console.WriteLine("DoSomethingAsyncEnd");
}

因为控制台没有SynchronizationContext上下文,如果没有上下文则会把TaskScheduler当做当前上下文继续运行,可以把这2行代码帖到上面winform里,观察到winform的不为null这个就是UI上下文,除了ui,asp.net上下文,其他很多情况下采用线程池上下文。所以捕获到上下文时候,我们的后续await后续同步的代码都想在原始的上下文中恢复运行,就比如在UI线程中调用DoSomethingAsync(),则这个MessageBox.Show("DoSomethingAsyncEnd");运行在UI线程,但是如果在线程池线程调用DoSomethingAsync(),则await后续同步的代码都在线程池线程上运行,所以需要使用ConfigureAwait(false),这个方法的意思是true尝试将延续任务(await后续同步的代码)送回原始上下文(UI)运行,false相反。

为什么避免使用Task.Wait或者Task.Result

原文:https://www.cnblogs.com/caiyangcc/p/14083727.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!