C# Task.ConfigureAwait方法能来做什么?

一.ConfigureAwait作用是什么?

Configures an awaiter used to await this System.Threading.Tasks.Task. 配置一个等待Task的awaiter

其实真的没有理解这句话的含义,希望有知道意义的可以告诉我一下..

二.场景:

1.在非UI程序中使用Task.ConfigureAwait:

先来看看不使用这个方法对于程序执行的效果是如何的:

static void Main(string[] args)
{
    Console.WriteLine("Main1:" + Thread.CurrentThread.ManagedThreadId);
    Task t = TestConfigureAwait();
    Console.WriteLine("Main2:" + Thread.CurrentThread.ManagedThreadId);
    Console.ReadLine();
}

public async static Task TestConfigureAwait()
{
     onsole.WriteLine("TestConfigureAwait1 thread is " +                 
                       Thread.CurrentThread.ManagedThreadId);
      await Task.Run(() =>
      {
          Thread.Sleep(1000);
          Console.WriteLine("task thread is " + 
                             Thread.CurrentThread.ManagedThreadId);
       });
       Console.WriteLine("TestConfigureAwait2 thread is " + 
                          Thread.CurrentThread.ManagedThreadId);
}

结果:

再来看一下如何使用:

C# Task.ConfigureAwait方法能来做什么?_第1张图片

程序中,编译器提醒我们,该方法和await更配哟。

此方法接收一个bool值,bool值代表 :

true to attempt to marshal the continuation back to the original context captured;otherwise, false.

true:试图将延续封送回捕获的原始上下文;false:反之。

好吧,太抽象,还是没看懂,我们直接来尝试一下。

①那么我们现在来使用这个方法,并传入true值:

public async static Task TestConfigureAwait()
{
     onsole.WriteLine("TestConfigureAwait1 thread is " +                 
                       Thread.CurrentThread.ManagedThreadId);
      await Task.Run(() =>
      {
          Thread.Sleep(1000);
          Console.WriteLine("task thread is " + 
                             Thread.CurrentThread.ManagedThreadId);
       }).ConfigureAwait(true);
       Console.WriteLine("TestConfigureAwait2 thread is " + 
                          Thread.CurrentThread.ManagedThreadId);
}

结果与之前不使用该方法一样。

②传入false:

也是一样,所以我这里有个疑问,这个方法对非UI程序应该是没有作用吧?

如果真是这样,那么我们也只能在UI程序中探寻真相了。

2.在UI程序中使用Task.ConfigureAwait:

这里我们使用Winform窗体程序,然后使用button按钮点击事件测试:

C# Task.ConfigureAwait方法能来做什么?_第2张图片

private void button1_Click(object sender, EventArgs e)
{
    Console.WriteLine("main1 thread:" + Thread.CurrentThread.ManagedThreadId);
    TestConfigureAwait();
    Console.WriteLine("main2 thread:" + Thread.CurrentThread.ManagedThreadId);
}
public async Task TestConfigureAwait()
{
    await Task.Run(() =>
    {
        Thread.Sleep(1000);
        Console.WriteLine("Task thread :" + Thread.CurrentThread.ManagedThreadId);
    });
    Console.WriteLine("TestConfigureAwait thread : " + 
                       Thread.CurrentThread.ManagedThreadId);
}

首先,不使用ConfigureAwait方法,执行程序,点击Button按钮产生结果:


使用:

当传入true:

public async Task TestConfigureAwait()
{
    await Task.Run(() =>
    {
        Thread.Sleep(1000);
        Console.WriteLine("Task thread :" + Thread.CurrentThread.ManagedThreadId);
    });
    Console.WriteLine("TestConfigureAwait thread : " + 
                       Thread.CurrentThread.ManagedThreadId);
}

结果:

和不使用结果一样。

好,通过这篇文章:https://blog.csdn.net/qq_38312617/article/details/104335783,我们可以知道,UI线程序执行带有await关键字的方式时,await后面的语句继续由调用方执行,那么我们考虑一下这种情况:

private void button1_Click(object sender, EventArgs e)
{
    Console.WriteLine("main1 thread:" + Thread.CurrentThread.ManagedThreadId);
    Task task = TestConfigureAwait();
    //等待task执行完成
    task.wait();
    Console.WriteLine("main2 thread:" + Thread.CurrentThread.ManagedThreadId);
}
public async Task TestConfigureAwait()
{
    await Task.Run(() =>
    {
        Thread.Sleep(1000);
        Console.WriteLine("Task thread :" + Thread.CurrentThread.ManagedThreadId);
    }).ConfigureAwait(true);
    Console.WriteLine("TestConfigureAwait thread : " + 
                       Thread.CurrentThread.ManagedThreadId);
}

调用方线程在执行TestConfigureAwait方法遇到await,返回继续执行自己的语句,当执行到task.wait时,调用方线程被阻塞等待task完成,而在TestConfigureAwait方法中task执行完成之后,就会去找调用方线程来继续执行接下来的语句,可调用方线程现在也正被阻塞着呢,所以互相等待就造成了经典的死锁问题。

解决死锁的方法有三种:

①将代码同步化,顺序执行,不存在争抢线程资源。

②不使用await关键字。

③使用ConfigureAwait(false)(将上述代码的ConfigureAwait(true)的true部分改为false):

await之后的代码便由执行task的线程继续执行了,正常返回打印结果,这下大家就其乐融融了~

在什么样的情况下应该使用Task.ConfigureAwait?

①UI程序中

②服务、Api以及一切可能会被UI调用的程序中

最后:多使用Task.ConfigureAwait来避免可恶的假死吧!

你可能感兴趣的:(C# Task.ConfigureAwait方法能来做什么?)