1
6
为什么要考虑提供异步API? API操作是IO绑定的还是CPU绑定的?(是因为等待IO完成需要很长时间,还是因为它占用大量CPU?) 如果是CPU绑定的,我会考虑是否真的需要提供异步版本,因为调用方总是可以通过threadpool将同步操作有效地转换为异步操作。 提供异步API的最大原因是针对IO绑定的操作。与其让线程等待高延迟IO操作,不如使用异步IO。这尤其会影响系统的可伸缩性。例如,如果您在一个同步IO操作上有一个服务器阻塞,那么问题就不算太严重了——您只是占用了一个线程。但是,同时执行1000个相同的操作,您将占用1000个线程(如果内存为每个线程提供1MB的堆栈),只需等待占用很少CPU周期的操作完成。最终结果-你有一个空闲的CPU,但正在消耗资源。 因此,例如,如果您自己正在编写一个套接字库,那么您肯定希望提供异步IO操作,这样库的用户就可以编写可伸缩的应用程序。 例如,如果您正在编写一个加密库,那么即使操作可能需要很长时间,也可能不需要提供一个异步API——反正它是CPU绑定的。如前所述,用户可以使其成为异步的。 最后,如果您正在编写一个IO绑定系统,该系统使用提供异步IO的低级API(例如,使用套接字类的FTP客户机),那么您可能还需要考虑提供异步版本的API。不过,这样做并不容易——只有当您使用低级API的异步函数时,才能提供可伸缩性优势。这很快就会把简单的同步逻辑变成非常复杂、难以调试的异步逻辑。主要的问题是,您以前通过局部变量轻松访问的所有状态信息最终都需要手动捕获,这样当下一个IO操作完成时,您的逻辑就知道接下来要做什么。 提供一个异步API,然后在内部调用同步IO操作,这是毫无意义的(尽管我已经看到了这一点)。给人一种可伸缩性的错觉,但是…不是! 当.NET 4.0出现时,其中一些可能会变得简单一些(尽管我认为从我所看到的情况来看,这仍然很棘手)。 同时,您可能希望查看Jeffrey Richter的异步枚举器库,它可以帮助简化这一过程(在一定程度上): Jeffrey Richter on his async enumerator Power threading library including async enumerator 希望这有帮助, Phil。 注意:如果要实现异步API,我建议您通过“Classic Begin/End”IAsyncResult API提供它。原因是,根据我的记忆,它应该更好地与.NET 4.0的任务并行库集成。 |
2
2
基于事件的异步模式更容易被新手理解,并且在IDE上有更好的支持。 另一方面,经典的异步模式允许您执行更多特定的操作,例如启动多个异步操作,并等待其中一个或所有操作的完成。 |
3
1
您是否提供这一点真正取决于您的方法将要做什么。如果在没有这个的情况下以异步方式使用对象足够简单,那么我将避免在对象中实现异步方法。 例如,当.NET 4被释放时,任务并行库将使异步使用同步对象成为一项微不足道的“任务”,这意味着只需编写一个版本的软件就很容易,并允许异步或同步使用它。今天使用threadpool相当容易。 然而,如果您的方法本质上是等待您控制之外的东西(例如:网络),那么拥有异步方法是至关重要的。在这种情况下,我认为应该支持这两个选项,即begin*()/end*()和*async()/*都已完成。这两种模式都有它们的用途,而且很容易实现。 如果你看 MSDN page on Asynchronous Programming 有一个很好的线索可以帮助你决定这是否合理:
注意“可能”这个词。对于我来说,这就是决定方法是否应该是异步的关键。如果一个任务要等待其他任务,它 可以 需要很长时间,或者 可以 立即返回,这超出了我的控制,那么它应该是异步的。 另一方面,如果 总是 要花很长时间才能运行,我宁愿把它留给调用者来决定如何处理它。将它推到另一个线程上特别容易:
但是,如果调用者已经在后台/单独的线程中工作,那么只需同步使用它就更容易了。.NET 4中的任务使其更加简单:
|
Coding Dog · Python异步函数不工作。继续跑 1 年前 |
cyka · 强制JavaScript等待单击(循环) 2 年前 |
CodeMonkey · 无法访问React[重复]中的对象值 2 年前 |
Tim · 为异步方法返回列表的最佳方式是什么? 2 年前 |
dapidmini · 未捕获的承诺嵌套异步函数承诺错误处理 2 年前 |