一、ConfigureAwait的作用
ConfigureAwait方法是Task类中的一个实例方法,它用于配置任务的运行上下文。运行上下文指的是任务在执行期间所处的环境,包括线程、同步上下文等。ConfigureAwait方法接受一个布尔值参数,用于决定是否捕获上下文。当参数为true时,表示任务会在之前的上下文中继续执行。当参数为false时,表示任务会在不同的上下文中执行。 ConfigureAwait方法的原理是通过设置Task对象的一个内部状态来实现的。当调用ConfigureAwait方法时,会创建一个新的Task对象,并将原始Task对象的状态复制给该新的Task对象。新的Task对象会在执行时,根据参数值决定是否将上下文捕获。
通俗的讲,ConfigureAwait可以取决任务之后的代码是继续返回主线程执行还是在新开的线程中继续执行。
二、代码示例
ConfigureAwait在界面中应用最明显:
private void button1_Click(object sender, EventArgs e) { MessageBox.Show($"开始运行,ThreadId:{Thread.CurrentThread.ManagedThreadId}", "button1_Click"); Test(); MessageBox.Show($"运行结束,ThreadId:{Thread.CurrentThread.ManagedThreadId}", "button1_Click"); } public static void Test() { var task = XXXAsync(); // 开启异步任务,比如下载某个资源 var resuslt = task.Result; // 获取异步任务的结果显示给用户,这里会阻塞当前ui线程直到异步线程返回结果 MessageBox.Show($"XXXAsync运行结束显示异步任务结果:{resuslt},ThreadId:{Thread.CurrentThread.ManagedThreadId}", "Test"); } private static async Task<string> XXXAsync() { await Task.Delay(1000); // 这里会导致死锁 //await Task.Delay(1000).ConfigureAwait(false); // 这样就不会死锁 MessageBox.Show($"XXXAsync运行结束,ThreadId:{Thread.CurrentThread.ManagedThreadId}", "XXXAsync"); return "XXXAsync.Result"; }
async /await 出现时var resuslt = task.Result会等待任务执行,直到XXXAsync()有返回结果才会继续执行主线程也就是var resuslt = task.Result在主线程中挂起,一直占用主线程,但await任务后 MessageBox.Show($"XXXAsync运行结束,ThreadId:{Thread.CurrentThread.ManagedThreadId}", "XXXAsync");代码是在同步执行,是在主线程上进行,由于主线程被var resuslt = task.Result一直占用,await代码就会无法在主线程上执行,出现卡死现象。
ConfigureAwait则会解决该问题,当ConfigureAwait(true)时,则是返回主线程执行await后续代码,也是默认情况出现卡死,ConfigureAwait(false)时就会解决该问题,await后的代码会在支线程继续执行,不会出现该问题。
注意: async /await 返回为task与var resuslt = task.Result连用时,await后的任务ConfigureAwait的属性设置为false避免假死。
在非界面代码上进行测试:
static void Main(string[] args) { Console.WriteLine("开始执行程序"); Console.WriteLine("这是主函数:{0}", Thread.CurrentThread.ManagedThreadId); var task = tt(); var result = task.Result; Console.WriteLine("运行结果为:"+result+" "+ Thread.CurrentThread.ManagedThreadId); Console.Read(); } public static async Task<string> tt() { await Task.Run(() => { Console.WriteLine("这是等待方法异步线程:{0}", Thread.CurrentThread.ManagedThreadId); }).ConfigureAwait(true); Console.WriteLine("这是异步方法剩余内容:{0}", Thread.CurrentThread.ManagedThreadId); return "异步方法完成"; }
await后续代码并没有返回主线程执行,而是直接在支线程执行,并没有出现卡死的情况。猜想或许只有在界面操作时才会出现假死情况!在后续中也会继续留意该问题!