我一直在为我的所有库应用异步最佳实践。基本上它意味着:
我在一个本质上是同步的库上工作。这意味着它只有同步方法。如果用户想要在不同于UI线程的单独线程上运行工作,他们可以使用Task.Factory
(调用者的责任)自己完成。
但是,在处理程序/方法/扩展点内,我们希望向用户显示一个消息框。这是一种异步方法(例如,WinRT ShowDialogAsync
)。然后,这给了我们以下选项:
:一种。将所有内容移至异步(因此我们可以选择在处理程序中使用await并且不阻止任何内容)。
public async Task MyMethodAsync()
{
await _messageService.ShowAsync();
}
优点是用户可以添加异步方法而无需使用.Wait()。缺点是我们作为一个图书馆(它不是真正的异步)。
我考虑过将所有内容设为异步,但我认为这也不是一个好主意。这将使所有的图书馆撒谎,但准备他们以防我们需要它。请记住,开箱即用的异步也会产生(小)性能影响。
B中。在需要用户输入的处理程序内,调用.Wait()
public void MyMethod()
{
_messageService.ShowAsync().Wait();
}
优点是,这将允许我们在同步方法中使用异步代码。但是......它永远不会从UI线程调用,因为_messageService会调度到UI线程(但它不能这样做,因为它仍在等待该方法,导致死锁)。当在Task.Factory.Run块中使用时,此方法将工作(但责任取决于最终用户):
await Task.Factory.Run(() => MyMethod());
问题
我觉得两者都有利有弊,但你会选择什么?让库谎言(A)或只允许从后台线程(B)调用该方法?或者我可能还有其他选择。
如果我选择A,这意味着每当用户请求将方法转换为异步签名方法时,我每次都必须碰撞主要版本(因为它实际上是一个重大变化)。
答案 0 :(得分:3)
当且仅当你有一个不会死锁的更快的同步方法时,定义一个同步方法。
我会说“如果要进行同步工作,请定义一个同步方法”。它的速度并不重要。调用者有责任确定它是否太慢并且他们需要使用Task.Run
。
但是,在处理程序/方法/可扩展性点
中
如果这是Observer类型的可扩展性,请考虑使用事件或可观察对象。
然而,听起来你想要更多的策略类型的可扩展性,你的调用代码必须根据回调的结果等待和/或改变它的行为。
我考虑过让所有东西都异步,但我认为这也不是一个好主意。
Async一直是指南,而不是严格的命令。它肯定适用于99%的情况,但这可能是例外之一。我会尽量不为了可能的异步策略模式而使库异步;我首先要研究其他扩展可能性。如果您将策略回调视为依赖项,则存在使库异步的有效参数(该库将是异步的,因为它的依赖性(可能)是异步的)。
正如您所发现的那样,没有干净的方法可以进行同步异步。有一些不同的hacks(例如从后台线程阻塞),但您首先需要决定是否需要从UI线程调用库。
如果这样做,那么只有两个选项:使库异步,或使用嵌套的消息循环。我强烈避免嵌套的消息循环,特别是在库中;我只是为了完整起见而提到它。
如果您可以强制要求用户只从非UI线程调用库,那么您可以应用其他黑客攻击。例如,阻止后台线程。
抱歉,没有一个简单的解决方案。
就我个人而言......如果图书馆需要异步策略,那么我会倾向于使库异步。但它确实取决于它是什么类型的库,是否存在向后兼容性问题等。我要研究的第一件事是不同类型的可扩展性点。
答案 1 :(得分:0)
你可以在这里阅读: https://msdn.microsoft.com/en-us/magazine/jj991977.aspx
始终异步
异步代码让我想起了一个人的故事,他提到世界被暂停在太空中,并立即被一位老太太挑战,声称世界停留在一只巨龟的背上。当那个男人询问乌龟站在什么地方时,那位女士回答说:“你是一个非常聪明的年轻人,但它一直是乌龟!”当你将同步代码转换为异步代码时,你会发现它有效最好的,如果异步代码调用并被其他异步代码调用 - 一直向下(或“向上”,如果你愿意)。其他人也注意到异步编程的传播行为,并将其称为“具有传染性”或将其与僵尸病毒进行比较。无论是海龟还是僵尸,异步代码往往会驱使周围的代码也是异步的。这种行为是所有类型的异步编程所固有的,而不仅仅是新的async / await关键字。
“始终异步”意味着您不应在不仔细考虑后果的情况下混合使用同步和异步代码。特别是,通过调用Task.Wait或Task.Result来阻止异步代码通常是个坏主意。对于那些将脚趾“踩踏”到异步编程中的程序员来说,这是一个特别常见的问题,它只转换应用程序的一小部分并将其包装在同步API中,因此应用程序的其余部分与更改隔离开来。不幸的是,它们遇到了死锁问题。在MSDN论坛,Stack Overflow和电子邮件上回答了许多与异步相关的问题后,我可以说这是迄今为止异步新手最常见的问题,一旦他们学会了基础知识:“为什么我的部分异步代码死锁?”