编写一个devise良好的asynchronous/非asynchronousAPI
我正面临着devise方法与执行networkingI / O(对于可重用的库)的问题。 我读过这个问题
c#5在APIdevise中等待/asynchronous模式
还有其他更接近我的问题。
所以,问题是,如果我想提供asynchronous和非asynchronous方法,我怎么devise这些?
例如,要公开一个方法的非asynchronous版本,我需要做类似的事情
public void DoSomething() { DoSomethingAsync(CancellationToken.None).Wait(); }
我觉得这不是一个好devise 我想build议(例如)如何定义私有方法,可以包装在公共的提供两个版本。
如果你想要最可维护的选项,只需要提供一个async
API,这个API不需要进行任何阻塞调用或者使用任何线程池线程。
如果您确实想要同时使用async
API和同步API,那么您将遇到可维护性问题。 你真的需要实现两次:一次async
和一次同步。 这两种方法看起来都差不多,所以最初的实现很简单,但是最后你会得到两个几乎相同的方法,所以维护是有问题的。
特别是,没有简单的方法来制作async
或同步的“包装器”。 Stephen Toub有关于这个问题的最好的信息:
- 我应该公开同步方法的asynchronous包装?
- 我应该公开asynchronous方法的同步包装?
(这两个问题的简短答案是“否”)
我同意Marc和Stephen(Cleary)。
(顺便说一句,我开始写这个作为斯蒂芬答案的评论,但是结果太长了;让我知道如果把这个写成答案或者不写就可以了,这就是斯蒂芬的答案,本着“提供最佳答案”的精神)。
它真的“依赖”:像Marc说的,知道DoSomethingAsync是如何asynchronous是很重要的。 我们都同意,使用“sync”方法调用“async”方法和“wait”没有意义:这可以用用户代码完成。 有一个单独的方法的唯一好处是有实际的性能增益,有一个实施,是在不同的情况下,并针对同步的情况。 如果“asynchronous”方法创build一个线程(或从一个线程池中获取),那么尤其如此:您最终得到的东西在下面使用两个“控制stream”,而“承诺”与它的同步看起来要在来电者的上下文。 这可能甚至有并发问题,取决于实施。
另外在其他情况下,像OP提到的密集I / O一样,可能值得有两种不同的实现。 大多数操作系统(Windows肯定)都针对I / O不同的机制针对两种情况进行了定制:例如,I / O操作的asynchronous执行和I / O操作在操作系统级别机制(如I / O完成端口)在内核开销(不是显着的,但不是空的)(毕竟他们不得不做记账,调度等等),而更直接的执行同步操作。 代码复杂性也有很大的不同,特别是在多个操作完成/协调的function中。
我会做的是:
- 对典型的使用情况和scheme有一些例子/testing
- 查看使用哪个API变体,何处和度量。 测量“纯同步”变体和“同步”之间的性能差异。 (不是针对整个API,而是针对less数几个典型案例)
- 基于测量,决定增加的成本是否值得。
这主要是因为两个目标在某种程度上相互对立。 如果你想要可维护的代码,明显的select是在asynchronous/等待方面实现同步(或者反过来说,只提供asynchronous变种,让用户“等待”)。 如果你想要性能,你应该以不同的方式实现这两个函数,以便利用不同的底层机制(从框架或操作系统)。 我认为它不应该从unit testing的angular度来看你是如何实际实现你的API。