93
  1. 有什么区别:

    • 异步,
    • 非阻塞,和
    • 基于事件的架构?
  2. 东西可以是异步的和非阻塞的(和基于事件的)吗?

  3. 编程中最重要的是什么:异步、非阻塞和/或基于事件的(或全部 3 个)?

如果你能提供例子,那就太好了。

之所以提出这个问题,是因为我正在阅读有关类似主题的这篇很棒的StackOverflow文章,但它没有回答我上面的问题。

4

5 回答 5

99

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

Non-Blocking 这个术语主要用于 IO。这意味着当您进行系统调用时,无论结果如何,它都会立即返回,而不会让您的线程进入睡眠状态(很有可能)。例如,非阻塞读/写调用返回他们可以做的任何事情,并期望调用者再次执行调用。例如 try_lock 是非阻塞调用。只有在可以获取锁的情况下才会锁定。系统调用的通常语义是阻塞的。read 将等到它有一些数据并将调用线程置于睡眠状态。

Event-base 这个术语来自 libevent。非阻塞读/写调用本身是无用的,因为它们不会告诉你“何时”应该回调它们(重试)。select/epoll/IOCompletionPort 等是从操作系统中找出“何时”这些调用有望返回“有趣”数据的不同机制。libevent 和其他此类库为各种操作系统提供的这些事件监视工具提供了包装器,并提供了一个一致的 API 来使用它跨操作系统运行。非阻塞 IO 与 Event-base 齐头并进。

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

于 2012-02-28T20:51:13.533 回答
21

在异步硬件中,代码要求某个实体做某事,并且在动作完成时可以自由地做其他事情;一旦动作完成,实体通常会以某种方式向代码发出信号。非阻塞架构将记录代码可能感兴趣的自发发生的动作,并允许代码询问这些动作发生了什么,但代码只有在明确询问这些动作时才会意识到这些动作。当事件自发发生时,基于事件的架构将肯定地通知代码。

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

在阻塞读取架构中,代码将等到 1,000 字节到达或决定放弃。

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

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

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

于 2012-04-13T19:16:09.273 回答
5

所以回答你的第一个和第二个问题:

非阻塞实际上与异步相同——你进行调用,稍后你会得到一个结果,但是当这发生时你可以做其他事情。阻塞则相反。在继续您的旅程之前,您等待电话返回。

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

异步是所有操作系统需要如何工作的基础——它们在后台为你完成了一些工作,并在它们完成了你所要求的事情时唤醒你的代码,当调用失败时,你会被告知它没有通过异常或某种返回代码/错误对象工作。

当你的代码要求一些需要一段时间才能响应的东西时,你的操作系统知道它可能会忙于做其他事情。您的代码 - 一个进程、线程或等效的块。您的代码在等待建立网络连接,或等待来自 HTTP 请求的响应,或等待读/写文件时,完全不知道操作系统中发生的其他事情,并且很快。您的代码可以“简单地”等待鼠标点击。在那段时间实际发生的是你的操作系统正在无缝地管理、调度和响应“事件”——操作系统正在寻找的东西,比如管理内存、I/O(键盘、鼠标、磁盘、互联网),其他任务,故障恢复等。

操作系统是该死的硬核。他们非常擅长向程序员隐藏所有复杂的异步/非阻塞内容。这就是大多数程序员通过软件达到我们今天所处的位置的方式。现在我们达到了 CPU 的限制,人们说可以并行完成以提高性能。这意味着异步/非阻塞似乎是一件非常有利的事情,是的,如果您的软件需要它,我可以同意。

如果您正在编写后端 Web 服务器,请谨慎操作。请记住,您可以以更便宜的方式横向扩展。Netflix / Amazon / Google / Facebook 显然是这条规则的例外,纯粹是因为使用更少的硬件对他们来说更便宜。

我会告诉你为什么异步/非阻塞代码是后端系统的噩梦......

1)它变成了对生产力的拒绝服务……你必须想得更多,而且你在这个过程中犯了很多错误。

2) 反应式代码中的堆栈跟踪变得无法辨认——很难知道什么叫做什么、什么时候、为什么以及如何。祝你调试顺利。

3)您必须更多地考虑事情是如何失败的,尤其是当许多事情按照您发送它们的方式返回时。在旧世界,你一次只做一件事。

4)测试更难。

5)更难维护。

6) 很痛苦。编程应该是一种快乐和乐趣。只有受虐狂喜欢痛苦。编写并发/响应式框架的人是虐待狂。

是的,我写过同步和异步。我更喜欢同步,因为 99.99 的后端应用程序都可以使用这种范例。毫无疑问,前端应用程序需要响应式代码,而且一直都是这样。

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

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

于 2018-02-21T23:05:40.217 回答
4

对我来说,非阻塞意味着线程中动作的执行不依赖于其他线程的执行,特别是不需要关键部分。

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

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

事件的概念是别的东西,粗略地说,就是当某事发生时你被告知。如果写操作是异步执行的,一旦写操作执行完毕,可以引发一个事件来通知系统的其他部分。其他部分将响应该事件。系统可以完全建立在事件上,作为组件之间通信的唯一方式(想想演员模型),但不一定非要如此。

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

于 2011-11-10T13:12:42.817 回答
2

通常,非阻塞架构基于方法调用,虽然它们可能在工作线程上执行很长时间,但不会阻塞调用线程。如果调用线程需要获取有关或从工作线程正在执行的任务的信息,则由调用线程来完成。

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

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

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

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

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

于 2011-10-28T17:01:55.463 回答