C#中的async/await和同步代码有什么区别?

发布时间 2023-03-27 22:49:12作者: HackerVirus

C#引入了async/await关键字,可以以同步代码的方式写异步代码,那使用await GetValueAsync()和GetValueAsync().Result或者直接使用同步方法GetValue()的区别在哪里(GetValueAsync()中设置了ConfigureAwait(false))?

可以使用代码来举出他们的区别吗?

 可以简单理解成:

await GetValueAsync()会释放调用线程,然后GetValueAsync会继续执行,出结果后以某种方式通知调用者,回来执行后续语句。至于是不是一开始的调用线程回来,取决于调用线程是否存在同步上下文,以及是否指定了ConfigureAwait(true)(默认就是)。相当于找人代练,自己出去干别的,完了对方通知你去接手或让朋友接手;

GetValueAsync().Result会阻塞当前线程,同时GetValueAsync在背后工作,完成后Task放行当前线程并返回结果。相当于找人代练,但自己在旁一直看着,一练好立马接手;

GetValue()与GetValueAsync().Result的表面效果类似,都会让调用线程“卡”一段时间,但本质不同。相当于自己操刀练,但在外面看来,你和上一种情况一样都是进了网吧一段时间。

上述说法成立的前提是,GetValueAsync和GetValue是实现良好的典型异步、同步方法,要不然带Async的方法完全可以全程同步实现,最后来个await Task.CompletedTask,又或者GetValue内部偏偏以异步实现,那就捉迷藏了属于是。

但是这里面涉及的东西不简单,比如await GetValueAsync()也并不是立即释放,得看GetValueAsync()里面的实现,如果它内部也是await另一个xxxAsync,还得看那个的实现,基本上是看调用链上最后返回Awaitable的时机。还有GetValueAsync().Result由于会阻塞调用线程,当GetValueAsync内部要通知你干点啥的时候,就会发生死锁,你在等它它在等你,用ConfigureAwait(false)相当于让它别通知你,通知别人,GetValue由于从头到尾只涉及单个线程,所以不存在死锁问题。

async/await这块我感觉还是要深入到鸭子类型Awaitable去理解,网上比如博客园有不少深入讲解的文章,想深入的话可以啃啃,我自己倒没有多深入,我写业务的,感觉使用来说够了。另可参看:

async await 和 同步本质上来说是“感觉” 上的一致,async await 本质上是一个状态机回调机制.
Expressions - C# language specification
打个比方

    class Program
    {
        static async Task Main(string[] args)
        {
            await Task.Yield();
            Console.WriteLine("Hello World!");
        }
    }


作者:知乎用户
链接:https://www.zhihu.com/question/495756868/answer/2200532439
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。