Async/Await回调行为疑问:为何t.Result会阻塞后续代码执行?
为什么
Console.WriteLine(t.Result)会阻塞后续代码执行? 嘿,这个问题戳中了很多异步编程初学者容易混淆的点,其实核心原因很简单:Task.Result和Task.Wait()本质上是完全一样的同步阻塞操作,只是一个返回结果、一个无返回值而已!
先理清楚你的代码执行流程
假设你的代码结构大概是这样的:
static void Main() { Task<string> t = GetUrlContentAsync(); Console.WriteLine(t.Result); // 这里会阻塞 Console.WriteLine("I am done"); } static async Task<string> GetUrlContentAsync() { HttpClient client = new HttpClient(); Task<string> getStringTask = client.GetStringAsync("https://example.com"); string urlContents = await getStringTask; return urlContents; }
当Main方法执行到t.Result时,发生了这些事:
- 之前启动的
GetUrlContentAsync任务确实在后台运行,甚至可能已经执行到await getStringTask这一步,让出了线程回到Main。 - 但**
Result属性会强制当前线程(也就是Main线程)停下来,同步等待整个t任务完全执行完毕**——不管任务内部有没有await,只要你调用Result,当前线程就会被阻塞,直到拿到任务的返回值。 - 只有当
t任务彻底完成、Result拿到结果后,Main线程才会继续执行下一行的Console.WriteLine("I am done")。
await和Result/Wait()的本质区别
你之所以困惑,是把异步等待和同步阻塞搞混了:
await是异步等待:它会释放当前线程,让线程去处理其他工作,等任务完成后再回调回来继续执行后续代码,全程不会阻塞线程。Result/Wait()是同步阻塞:它们会直接“卡住”当前线程,什么都不做,直到任务结束,完全剥夺了线程的异步能力。
如果你想让"I am done"先执行
要实现你预期的“先回到Main执行I am done,再处理任务结果”,需要把Main改成异步方法(C# 7.1及以上支持),并且不要用Result,而是用await异步等待任务:
static async Task Main() { Task<string> t = GetUrlContentAsync(); // 先执行这行,不用等任务完成 Console.WriteLine("I am done"); // 异步等待任务结果,不会阻塞线程 string result = await t; Console.WriteLine(result); }
这样执行顺序就会是先输出I am done,等任务完成后再输出网址内容。
内容的提问来源于stack exchange,提问作者Tony
相关产品推荐
相关产品推荐

