一.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);
}
结果:
再来看一下如何使用:
程序中,编译器提醒我们,该方法和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按钮点击事件测试:
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来避免可恶的假死吧!