事件回路是处理事件的一种范式,不同于你典型的单行或多行应用程序.
您的请求被细分为同步“ 事件” , 在一个循环中执行, 以改善性能, 并最小化跨线程同步 。
它被Node.js作为他们事件处理的骨干,同时也被Redis和Nginx等多款其他技术所出名.
我将在这篇文章中解释这个范式产生的原因,以及它试图优化的内容.
到最后你会更聪明一点, 动机 - 为什么事件循环?
为了理解为什么我们需要事件循环,我们将探索一个简单而关键的例子。
使用这个直截了当的HTTP请求代码,它发送一个请求,然后尝试读取套接字的响应: 我们做两件事 数据输出和数据输入。
这两种动作最终会触发通过写取数据的内核的syscalls.
就花费在CPU上的时间而言,这相对成本较低;发送出包需要的时间很少,最终读取响应也会花费很少的CPU时间.
损失的关键时间是等待服务器回应我们.
将屏蔽此线程,直到答复可用,这意味着此线程在这段时间内不能用于其他处理。
如果我们的服务是单行道的,这意味着我们不能平行地提出任何请求,并且被卡住等待任何之前的请求完成.
但是,当然,大多数服务不是单行本,所以这不是个大问题?
让我们继续用实例代码, 想象我们正用多个线程来处理这些请求。
好吧,现在我们做饭了!
我们有多个线程处理 请求清单, 我们已经10X'ed我们的吞吐量,惊人。
但我们不是来创造另一个多条线的, 那么这里有什么问题?
一个主要问题是,我们现在管理着10个线程, 它们必须同步才能从...
通过锁进行同步可以增加很多的间接费用,减慢我们的程序(因此我们可能没有在这里实际获得10x增益. ).
另一个问题是,我们的吞吐量有一个确定的上限 - 10个请求。
我们可以解决它 通过撞出线条的数量。
假设我要10克请求作为我的吞吐量 -- 我只要把它增加到10克,一切都会好起来的,对吧?
没有 除了增加同步的间接费用外,我们还有其他一些问题要提出(正如俗话说的,没有免费午餐之类的事情......): 管理每个线程( 线程缩放) 的额外内存 与其它线程协调 - > 纬度( 等位缩放) 更多用于CPU的上下文开关 。
这些不是免费的,而且可能是高通货率的拖延。
更多线索 \ 更多CPU缓存行打!
我们的单行程序并不存在这些问题,所以也许我们可以以不同的方式解决这个问题.
让我们看看我们能不能拿回 单行道魔法,并开始平行处理!
输入事件循环 正如你可能猜到的, 我们的事件循环会是单一的线程。
那么我们如何避免我们之前看到的阻断电话?
两件事——范式转变和内核的一点帮助.
范式转变:与事件合作 现在我们不能直接用我们的用户代码调用, 我们需要返回一些东西来表达我们阅读的意图 以及继续执行我们代码的方法。
让我们称之为"某事"。
具体地说,一个事件描述了进行类似或类似音节调用的意图,以及应该处理音节调用结果的指针.
把它放进代码里, 班级会看起来像这样: 打破它,我们的活动班级包含: 说我们想对An执行什么行动 来描述事件的结果
