不幸的是,对于任何坚持使用一些旧技术的人来说,这不是一个 Select .
我有一个article人讨论了几种可能的异步同步方法,并简要讨论了每种方法的缺点.
例如,.NET框架中的Web服务(Asmx)不支持TAP.
不支持,但ASMX确实支持APM,您可以编写一个short interop layer来将您的核心分路逻辑expose 给ASMX,并始终保持异步状态.在Nito.AsyncEx中,有大约examples on SO个关于如何做到这一点的文档,还有大约TAP-to-APM helpers个文档,它们使得互操作层非常干净.
很少有require同步胜过异步的情况;当转换代码不是业务优先事项时,保留一些真正应该是异步的代码通常是一个务实的决定.
在大型传统解决方案中,维护重复调用链(同步和异步)可能非常令人生畏和厌倦.
100%同意.
我更喜欢的解决方案是Brownfield Async article中"布尔参数黑客"的更现代版本,这最初是Stephen Toub在那篇文章的技术 comments 中向我展示的.这是一种让代码保持一路异步或一路同步的技术,但不需要任何逻辑复制.
最近,Stephen Toub在他的article on .NET 7 performance improvements篇文章(这是一篇很长的文章;搜索与阅读和写作表现有关的最后一项改变)中展示了更现代版本的"布尔论点黑客"(Boolean Argument Hack),找到相关部分.我拿出那颗Ruby ,写了一个more specific blog post about it分.代码起初看起来很奇怪,但它是一种非常强大的技术,这是我推荐给所有现代库的.
此实施可能存在哪些缺陷?
此实现安装包含工作队列的自定义SynchronizationContext
,对初始工作项进行排队,然后同步等待其工作队列完成.它与我的AsyncEx库中的AsyncContext
相似.我相信实现最初是从this old forum post开始的,我在几个地方看到过它的复制,通常会有一条 comments ,比如"我不知道这是如何工作的",老实说,这对我来说有点可怕.我从SO和其他地方拿代码,但only后完全理解它.
您可以说它是从the Brownfield Async article开始的"嵌套消息循环黑客"的变体.AsyncHelpers.RunSync
控制当前线程,并将其转换为消息泵,处理自己的工作队列.它安装了自己的SynchronizationContext
来捕获async
个延续(which by default resume on the captured SynchronizationContext
or TaskScheduler
正如我在我的博客上描述的那样).
所以,你将要遇到的角落 case 都与那SynchronizatonContext
个掉期有关.可能不可能列出一个详尽的 list ,但这里有一些我头顶上的担忧:
- 某些组件需要特定的
SynchronizationContext
.一个例子是在核心ASP.NET之前的日子里,如果SynchronizationContext.Current
不是AspNetSynchronizationContext
,一些ASP.NETAPI将只有hang.我真的不知道他们为什么要这么做,但这是我在多年前try 这种黑客攻击时观察到的行为.作为另一个例子,一些UI组件将验证它们在正确的同步上下文中(其他组件验证它们在正确的thread上,如果SyncCtx被交换,它仍然工作得很好).
- 有些组件捕获
SynchronizationContext
以备后用,但这里使用的SynchronizationContext
具有有限的生命周期;一旦任务完成,整个SyncCtx就会被拆除.因此,在SyncCtx被拆除后,不能使用任何像Progress<T>
或在该SyncCtx上观察到的Rx观察.
- 此解决方案安装单线程上下文,然后在其上同步阻塞.因此,它解决了一类异步同步问题,但如果它调用的任何东西执行阻塞样式的异步同步,它肯定会死机.
- 最后一个问题是我最大的担忧之一,但也是最难解释的.在我的文章中,我把它写成"意想不到的再入".如果在UI线程(或更具体地说,STA线程)上运行,这种方法可能会产生令人惊讶的结果.CBrumme有一些很棒的博客文章,讲述了.NET运行时如何在阻塞时执行some STA泵送;遗憾的是,这些文章在几年前微软改变了他们的博客URI方案时被删除了.从本质上讲,这意味着某些Windows消息可能会被UI线程处理,即使从托管的Angular 来看,它被"阻止"了;这可能会导致您的代码的某些部分运行,而不是作为
RunSync
的一部分运行,而不是作为窗口的主消息处理循环运行.现在,这些帖子被删除了,这modern .NET Core AutoResetEvent.WaitOne
ends up at WaitForMultipleObjectsIgnoringSyncContext
个帖子,像sounds这个名字一样,可能不是部分抽水,所以也许这不再是真的了.但对于我自己来说,我会非常谨慎地在STA/GUI线程上做这样的事情.
总之,这不是我推荐的方法.我建议改用泛型-值-类型-约束接口方法.但是,如果您对所有将同步运行的代码有很强的了解,并且确保不会遇到上述情况,那么它将是可以接受的.