C#的async和await关键字是什么?如何使用?

星降
发布: 2025-09-11 09:43:01
原创
727人浏览过
async和await通过异步非阻塞方式避免UI卡顿,提升响应性;其底层由编译器生成状态机实现,基于Task模型管理异步操作;使用时需避免死锁、慎用async void,并合理处理异常与上下文切换。

c#的async和await关键字是什么?如何使用?

C#中的

async
登录后复制
await
登录后复制
关键字是现代C#异步编程的核心,它们提供了一种编写非阻塞代码的简洁方式,让程序在等待I/O操作(如网络请求、文件读写、数据库查询)完成时,能够释放当前线程去处理其他任务,从而提高应用程序的响应性和吞吐量。简单来说,它们让异步代码看起来和写同步代码一样直观。

解决方案

要理解

async
登录后复制
await
登录后复制
,我们得先从它们解决的问题说起。想象一下,你正在写一个桌面应用,需要从网上下载一张大图。如果用传统的同步方式,下载过程中你的应用界面就会“卡死”,用户体验极差。
async
登录后复制
await
登录后复制
就是为了解决这类问题而生。

当一个方法被标记为

async
登录后复制
时,它就表明这个方法内部可能包含一个或多个
await
登录后复制
表达式。而
await
登录后复制
关键字,则只能在
async
登录后复制
方法中使用,它告诉编译器:“嘿,我这里要等待一个异步操作完成,在等待期间,当前线程可以去做别的事情,等操作完成了再回来从这里继续执行。”

具体来说,

await
登录后复制
后面通常跟着一个
Task
登录后复制
Task<T>
登录后复制
对象。当执行到
await
登录后复制
时:

  1. 如果被
    await
    登录后复制
    的异步操作(比如
    HttpClient.GetStringAsync()
    登录后复制
    )还没有完成,
    await
    登录后复制
    会立即将控制权返回给调用者。此时,当前方法并没有结束,它只是“暂停”了,并且注册了一个回调,告诉系统当异步操作完成后,从暂停的地方继续执行。
  2. 当异步操作完成时,系统会调度剩余的代码继续执行,通常是在捕获到的同步上下文(例如UI线程的上下文)或线程池线程上。

这样一来,耗时的操作就不会阻塞主线程(比如UI线程),用户界面就能保持响应,程序也能更高效地利用系统资源。

C#中async/await如何避免UI卡顿,提升用户体验?

这是一个非常实际的问题,也是

async/await
登录后复制
最直接的价值体现。在没有
async/await
登录后复制
的日子里,我们为了避免UI卡顿,不得不手动创建新线程,然后通过
Invoke
登录后复制
Dispatcher.BeginInvoke
登录后复制
等机制,将结果安全地传回UI线程更新界面。这过程复杂、容易出错,而且代码可读性很差。

async/await
登录后复制
的出现,极大地简化了这一过程。当你在UI线程上调用一个
async
登录后复制
方法,并在其中
await
登录后复制
一个耗时操作时,
await
登录后复制
会智能地捕获当前的同步上下文。这意味着,当异步操作完成后,
await
登录后复制
后面的代码会尝试在捕获到的那个上下文中继续执行。对于UI应用程序来说,这个上下文就是UI线程。

所以,当一个网络请求在后台线程完成时,

await
登录后复制
会自动确保更新UI的代码(比如
myTextBox.Text = result;
登录后复制
)是在UI线程上执行的,你不需要再手动去处理线程切换。这就像是
await
登录后复制
在说:“你去忙吧,我来帮你看着,等结果回来了,我会敲门告诉你,并且帮你把结果送到你手上。” 这样,UI线程在等待期间可以自由地处理用户的点击、拖拽等事件,从而避免了“假死”现象,大大提升了用户体验。它不仅让代码更简洁,还从根本上改变了我们编写响应式应用程序的方式。

async和await的底层原理是什么?它们与Task有何关系?

要深入理解

async
登录后复制
await
登录后复制
,就必须触及其底层原理和与
Task
登录后复制
的关系。这并不是什么魔法,而是编译器和.NET运行时协同工作的结果。

从根本上说,

async
登录后复制
await
登录后复制
是编译器语法糖。当你标记一个方法为
async
登录后复制
并使用
await
登录后复制
时,C#编译器会将其重写(rewrite)成一个状态机(state machine)。这个状态机是一个复杂的类,它包含了原始方法中的所有局部变量、参数,以及一个记录当前执行到哪一步的状态变量。

阿里云-虚拟数字人
阿里云-虚拟数字人

阿里云-虚拟数字人是什么? ...

阿里云-虚拟数字人2
查看详情 阿里云-虚拟数字人

Task
登录后复制
(或
Task<T>
登录后复制
)则是异步操作的代表。当你调用一个返回
Task
登录后复制
的方法时,你并没有立即得到结果,而是得到了一个承诺(Promise),这个承诺代表了未来的某个时间点会有一个结果。
Task
登录后复制
对象本身包含了操作的状态(是否完成、是否出错、结果是什么等)。

await
登录后复制
遇到一个未完成的
Task
登录后复制
时,它会:

  1. 保存当前方法的状态(局部变量、指令指针等)。
  2. 将控制权返回给
    async
    登录后复制
    方法的调用者。
  3. 注册一个回调到
    Task
    登录后复制
    上,告诉
    Task
    登录后复制
    一旦完成,就通知状态机继续执行。

Task
登录后复制
完成时,状态机就会被唤醒,从之前暂停的地方继续执行。整个过程,线程可能已经切换了多次,但对于开发者来说,代码看起来仍然是顺序执行的。这种机制避免了手动管理回调和线程的复杂性,将异步编程从“回调地狱”中解救出来。
Task
登录后复制
就是这个异步操作的“句柄”或“票据”,
async
登录后复制
await
登录后复制
则是操作这个票据的语法糖,让整个流程变得平滑和易于理解。

在使用async/await时常见的陷阱和最佳实践有哪些?

尽管

async/await
登录后复制
极大地简化了异步编程,但如果不注意,也容易踩坑。

一个常见的陷阱是死锁,尤其是在UI应用程序中。当你在一个同步方法中,通过

.Result
登录后复制
.Wait()
登录后复制
来阻塞性地等待一个
async
登录后复制
方法的完成时,如果这个
async
登录后复制
方法在内部又尝试回到UI线程(通过捕获的同步上下文),而UI线程又被
.Result
登录后复制
.Wait()
登录后复制
阻塞了,那么就会发生死锁。UI线程在等待异步方法完成,异步方法在等待UI线程空闲以继续执行,形成循环等待。

最佳实践之一是:永远不要在同步代码中阻塞性地等待异步操作完成,除非你确定没有同步上下文需要捕获(例如在控制台应用中)。如果必须等待,考虑使用

ConfigureAwait(false)
登录后复制
来避免捕获上下文,但更好的做法是让整个调用链都变成异步的。

另一个陷阱是使用

async void
登录后复制
async void
登录后复制
方法主要用于事件处理器,它无法被
await
登录后复制
,这意味着你无法知道它何时完成,也无法捕获它抛出的异常。一旦
async void
登录后复制
方法抛出未处理的异常,它会直接崩溃整个应用程序,而不是像
Task
登录后复制
那样将异常封装起来。因此,除了事件处理器,尽量避免使用
async void
登录后复制

此外,异常处理也需要注意。在

async
登录后复制
方法中,
await
登录后复制
会像同步方法一样,将异步操作抛出的异常重新抛出。所以,你可以像处理同步代码一样,使用
try-catch
登录后复制
块来捕获异步操作中的异常。这比传统的回调模式下的异常处理要直观得多。

最后,性能考量。虽然

async/await
登录后复制
不会引入太多额外的开销,但过度细化异步操作,或者在不必要的地方使用
async/await
登录后复制
,也可能带来不必要的上下文切换开销。对于CPU密集型任务,
async/await
登录后复制
并不能直接提升性能,因为它们主要用于I/O密集型任务。对于CPU密集型任务,更适合使用
Task.Run
登录后复制
将其放到线程池中执行,以避免阻塞主线程。记住,
async/await
登录后复制
的核心是“不阻塞”,而不是“更快地完成计算”。

以上就是C#的async和await关键字是什么?如何使用?的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号