异步,非阻塞,基于事件的体系结构之间有什么区别?


84
  1. 之间有什么区别:

    • 异步
    • 非阻塞,和
    • 基于事件的架构?
  2. 事物既可以是异步的又可以是非阻塞的基于事件的)吗?

  3. 在编程中,最重要的是要拥有一些东西:异步,非阻塞和/或基于事件的(或全部基于3个)?

如果您可以提供示例,那就太好了。

有人问这个问题是因为我在阅读有关类似主题的出色StackOverflow文章,但没有回答我上面的问题。

Answers:


91

异步 从字面上看,异步意味着不同步。电子邮件是异步的。您发送邮件,您不希望立即收到答复。但这不是非阻塞的。从本质上讲,这意味着一种体系结构,其中“组件”相互发送消息而不会立即期望响应。HTTP请求是同步的。发送请求并获得回复。

非阻塞 该术语通常与IO一起使用。这意味着当您进行系统调用时,它将立即返回,无论其结果如何,都不会使线程进入睡眠状态(很有可能)。例如,无阻塞的读/写调用将以其所能做的一切返回,并期望调用方再次执行该调用。例如try_lock是非阻塞调用。只有可以获取锁,它才会锁定。系统调用的常规语义正在阻塞。读取将等待,直到它具有一些数据并将调用线程置于睡眠状态。

基于事件的 术语该术语来自libevent。无阻塞的读/写调用本身是没有用的,因为它们不会告诉您“何时”您应该给他们回叫(重试)。select / epoll / IOCompletionPort等是用于从操作系统中找出“何时”这些调用返回“有趣”数据的不同机制。libevent和其他此类库为各种操作系统提供的这些事件监视功能提供了包装,并提供了可在整个操作系统上运行的一致API。非阻塞IO与基于事件的IO并驾齐驱。

我认为这些术语重叠。例如,HTTP协议是同步的,但使用非阻塞IO的HTTP实现可以是异步的。同样,无阻塞的API调用(例如read / write / try_lock)是同步的(它立即给出响应),但是“数据处理”是异步的。


2
关于非阻塞的优点是需要不断轮询,而异步可以基于推送。
亚历山大·托斯汀

您将同步定义为接收即时响应,但是当我用Google同步时,所有词典都将其定义为“同时发生”,而不是“立即响应”。
IntelliData,2016年

4
发送电子邮件但不希望得到答复时如何阻止我?在等待响应时,我可以考虑自己的事。
Koray Tugay

20

在异步硬件中,代码要求某个实体执行某项操作,而在操作完成时可以自由地执行其他操作。动作完成后,实体通常会以某种方式发出代码信号。非阻塞体系结构将记录代码可能感兴趣的自发发生的动作,并允许代码询问发生了哪些此类动作,但是代码只有在明确询问这些动作时才会意识到这些动作。基于事件的体系结构将在事件自发发生时肯定地通知代码。

考虑一个串行端口,代码将从该端口接收1,000个字节。

在分块读取架构中,代码将等待,直到到达1,000个字节或决定放弃为止。

在异步读取体系结构中,代码将告诉驱动程序它需要1,000字节,并在到达1,000字节时得到通知。

在非阻塞体系结构中,代码可以随时询问已到达多少字节,并且在认为合适时可以读取任何或所有此类数据,但是唯一知道何时所有数据到达的唯一方法是询问。如果代码要在第1000个字节到达后的四分之一秒内查找,则必须每四分之一秒左右检查一次。

在基于事件的体系结构中,任何数据到达时,串行端口驱动程序都会通知应用程序。驱动程序不会知道应用程序需要多少字节,因此应用程序必须能够处理小于或大于应用程序所需数量的通知。


5

因此,回答您的第一个和第二个问题:

非阻塞实际上与异步相同-您进行调用,稍后会得到结果,但是在这种情况下,您可以执行其他操作。阻塞则相反。在继续旅程之前,您需要等待电话返回。

现在,异步/非阻塞代码听起来绝对很棒,确实如此。但是我有警告的话。在受限环境(例如手机)中工作时,异步/非阻塞非常有用。请考虑使用有限的CPU /内存。这对于前端开发也很有用,因为您的代码需要以某种方式对UI小部件做出反应。

异步对于所有操作系统的工作方式至关重要-它们会在后台为您完成操作,并在完成您所要求的操作时唤醒您的代码,而当调用失败时,您会被告知没有通过异常或某种返回码/错误对象工作。

当您的代码要求花一些时间才能响应时,您的操作系统知道它会忙于做其他事情。您的代码-进程,线程或等效块。在等待建立网络连接时,或者在等待来自HTTP请求的响应时,或者在等待读取/写入文件时,您的代码完全忽略了操作系统中正在发生的其他事情。以此类推。您的代码可能“仅”在等待鼠标单击。那时实际发生的事情是您的OS无缝地管理,调度和响应“事件”,即OS寻找的事情,例如管理内存,I / O(键盘,鼠标,磁盘,互联网),其他任务,故障恢复等

操作系统是frickin的核心。他们真的很擅长向程序员隐藏所有复杂的异步/非阻塞内容。这就是大多数程序员使用软件达到如今的状态的方式。现在我们正在达到CPU极限,人们说可以并行完成一些事情以提高性能。这意味着异步/非阻塞似乎是一件非常有利的事情,是的,如果您的软件需要它,我可以同意。

如果要编写后端Web服务器,请谨慎操作。请记住,您可以以更低的价格水平缩放。Netflix / Amazon / Google / Facebook是该规则的明显例外,纯粹是因为这样做对他们来说使用更少的硬件会更便宜。

我将告诉您,为什么异步/非阻塞代码是后端系统的噩梦...。

1)这成为对生产力的拒绝服务……您不得不多考虑,并且在此过程中会犯很多错误。

2)反应式代码中的堆栈跟踪变得难以理解-很难知道什么叫做什么,何时,为什么以及如何。祝您调试顺利。

3)您必须更多地考虑事情如何失败,尤其是当许多事情重新出现时,如何发送它们。在旧世界,您一次只能做一件事。

4)很难测试。

5)很难维护。

6)这很痛苦。编程应该很有趣。只有受虐狂喜欢痛苦。编写并发/反应框架的人是虐待狂。

是的,我已经编写了同步和异步。我更喜欢同步,因为这种范例可以实现99.99的后端应用程序。前端应用程序毫无疑问需要响应式代码,而这一直都是这种方式。

  1. 是的,代码可以是异步的,非阻塞的和基于事件的。

  2. 编程中最重要的事情是确保您的代码能够正常工作并在可接受的时间内做出响应。坚持这一关键原则,您就不会出错。


**更新**在使用Go并深入了解通道和go例程之后,我不得不说我确实喜欢使我的代码更加并发,因为该语言的构造完全摆脱了Sadist框架编写者的痛苦。在异步处理的世界里,我们有一个“安全词”,那就是“ Go!”。
user924272

4

对我来说,非阻塞意味着一个线程中某个动作的执行不依赖于其他线程的执行,特别是不需要临界区。

异步意味着执行发生在调用方流程之外,并且可能会延迟执行。执行通常发生在另一个线程中。

读取并发数据是非阻塞的(无需锁定),但是是同步的。相反,以同步方式同时写入数据会阻塞(需要排他锁)。从主流的角度来看,使其成为非阻塞状态的一种方法是使写入异步并推迟其执行。

事件的概念是另外一回事,从广义上讲,这意味着发生某事时会通知您。如果写入已异步执行,则一旦执行了写入操作,便可以引发一个事件以通知系统的其他部分。其他部分将响应该事件。系统可以仅基于事件构建,作为在组件之间进行通信的唯一方法(例如参与者模型),但是不一定必须如此。

这三个术语是相关的,但对我来说是不同的概念。可能是人们以某种​​可互换的方式使用它们。


2

通常,非阻塞体系结构基于方法调用,尽管它们可能在工作线程上长时间执行,但不会阻塞调用线程。如果调用线程需要获取有关工作线程正在执行的任务或从中获取信息的信息,则由调用线程来决定。

基于事件的体系结构基于响应于触发的事件而执行的代码的概念。代码执行的时间通常不是确定性的,但是事件可能会调用阻塞方法。仅仅因为系统是基于事件的,并不意味着它所做的一切都不会阻塞。

通常,异步体系结构是基于事件的非阻塞体系结构。

进行异步调用时,将向提供同步服务的API注册事件处理程序,以便通知调用者该调用者感兴趣的事情已经发生。然后,调用立即返回(非阻塞行为),并且调用者可以自由继续执行。当事件被发回到调用过程时,它们将在该过程中的某个线程上进行处理。

重要的是要了解事件是否将在同一线程上处理,因为这会影响执行的非阻塞性质,但是我个人并不知道任何在单个线程上执行异步执行管理的库。

我删除了上面的段落,因为它并非严格按照说明正确。我的意图是说,即使系统中的操作是非阻塞的,例如调用OS设备并继续执行,单线程执行的性质也意味着在触发事件时,它们将与用于在线程上计算时间的其他处理任务。


您的最后一段与您的声明“异步体系结构是……非阻塞性”是否矛盾
尼克

我想我在解决问题的“定义”部分方面做得不好。我将发布更新。但是,没有,单线程执行的本质是,每一个操作本质上是堵在运行时,这使得异步更加有用。
2011年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.