省略async关键字有何差异?async/await模式场景技术问询
两种写法的核心差异与async关键字的必要性分析
先明确:你的两个版本在语法合法性、行为逻辑上有本质区别,async绝非无用的装饰,下面拆解具体差异:
1. 返回值与语法合法性
- 不带
async的版本:你写的是Function但没返回值,VB会直接编译报错。就算补上Return Task.Run(...),它的返回类型是Task,但调用者如果没接住这个返回值,就完全没法跟踪任务状态。 - 带
async的版本:Async Function在VB中默认返回Task(无返回值场景),编译器会自动帮你生成返回逻辑——哪怕你没写Return,它也会返回一个标记为完成的Task,语法上完全合法。
2. 异常处理逻辑
- 不带
async的版本:如果Task.Run里的耗时代码抛异常,这个异常会被封在返回的Task里,但要是你没返回这个Task,或者调用者没等待它,就会变成未观察到的任务异常——旧版.NET可能直接崩进程,新版会静默但丢警告,异常彻底失控。 - 带
async的版本:async函数会自动捕获内部任务的异常,把它传到返回的Task里。后续调用者只要用Await等待,就能在调用上下文里正常捕获并处理这个异常,不会出现失控情况。
3. 编译后的底层逻辑
- 不带
async的版本:就是普通函数,执行Task.Run后直接返回,没有额外的状态机生成,性能上略优但灵活性差。 - 带
async的版本:编译器会为它生成一个异步状态机,哪怕你现在没用到Await,状态机依然存在。这会有微小的性能开销,但好处是后续扩展时,你可以直接在函数里加Await调用其他异步方法,完全不用重构函数结构。
4. 调用者的使用体验
- 不带
async的版本:调用者如果想等任务完成,必须手动拿Task.Run的返回值去Await,但你的代码没返回,调用者根本做不到,完全不知道任务什么时候结束,更没法在完成后做后续操作。 - 带
async的版本:调用者可以直接Await MyLongRunningFunction(),优雅等待任务完成,还能在后续安全更新UI(比如按钮点击事件改成async后,await完直接操作控件),完全符合.NET异步编程的规范。
关于async的必要性
如果只是单纯启动一个后台任务,修正返回值后的无async版本也能跑,但绝对不是最佳实践。一旦你后续要扩展函数逻辑(比如在耗时任务前后加异步IO操作),带async的版本可以无缝适配,不用大改代码结构。另外,配合按钮事件的async改造,能更安全地处理任务完成后的UI更新:
Private Async Sub Button_Click(sender As Object, e As EventArgs) Await MyLongRunningFunction() ' 这里可以直接更新UI,已经回到UI线程了 End Sub
内容的提问来源于stack exchange,提问作者Sam Marrocco
相关产品推荐
相关产品推荐

