我一直在考虑像React这样的代码和库,它们会自动,很好地对事件发生时做出反应,并且想知道如何在较低的C ++和机器代码级别上实现所有这些功能。
我似乎无法弄清楚是否可以通过其他线程上运行的while循环来实现类似事件监听器的其他方式。
那么,这一切都在幕后吗?只是一路循环下去?例如,像RethinkDB,它宣传自己为具有repubsub库的“实时数据库” 。“订阅”方法是否仅在后台使用while循环实现?我似乎找不到任何信息。
就像插座和东西一样。当计算机正在“侦听”套接字连接的端口时,该计算机是否正在运行类似以下内容的内容:
while(1) { if (connectionFound) { return True; } }
还是我想念的东西?
javascript和node.js等待的实际事件根本不需要循环。实际上,它们需要0%的CPU时间。
硬件
如果我们真的需要了解节点(或浏览器)内部的工作方式,那么不幸的是,我们必须首先了解计算机的工作方式-从硬件到操作系统。是的,这将是一次深潜,请耐心等待。
这是一个伟大的发明,但也是一个潘多拉魔盒-Edsger Dijkstra
是的,以上引用来自同一“ Goto认为有害” Dijkstra。从一开始就将异步操作引入计算机硬件被认为是一个非常困难的话题,即使对于业内的一些传奇人物而言。
引入了中断以加快I / O操作。硬件不需要将软件以无限循环的方式轮询某些输入(从而节省了CPU时间来完成有用的工作),而是将信号发送给CPU以告知事件已发生。然后,CPU将挂起当前正在运行的程序并执行另一个程序来处理中断- 因此我们将这些函数称为中断处理程序。 “ handler” 一词一直在堆栈中一直停留在GUI库中,GUI库将回调函数称为“事件处理程序”。
Wikipedia实际上有一篇相当不错的关于中断的文章,如果您不熟悉它并想了解更多信息:https : //en.wikipedia.org/wiki/Interrupt。
如果您一直在关注,您会注意到中断处理程序的概念实际上是回调。您将CPU配置为在事件发生后的某个时间调用函数。因此,即使回调也不是一个新概念-它比C更旧。
中断使现代操作系统成为可能。没有中断,CPU将无法暂时停止程序以运行OS(嗯,这是协作式多任务处理,但现在暂时忽略它)。操作系统的工作方式是在CPU中设置硬件计时器以触发中断,然后告诉CPU执行程序。运行您的操作系统的正是此定时定时器中断。
除了计时器外,操作系统(或更确切地说是设备驱动程序)还为I / O设置了中断。当发生I / O事件时,操作系统将接管您的CPU(或多核系统中的一个CPU),并检查其数据结构以处理下一步处理I / O的过程(这称为抢先式多任务处理)。
从键盘和鼠标存储到网卡的所有内容都使用中断来告知系统要读取的数据。如果没有这些中断,监视所有这些输入将占用大量CPU资源。中断是如此重要,以至于它们通常被设计成USB和PCI等I / O标准。
现在我们对此有了一个清晰的了解,我们可以了解节点/ javascript如何实际处理I / O和事件。
对于I / O,各种OS具有提供异步I / O的各种不同API-从Windows上的重叠I / O到Linux上的轮询/ epoll,再到BSD上的kqueue到跨平台的select()。Node在内部将libuv用作这些API的高级抽象。
尽管细节不同,但这些API的工作方式相似。本质上,它们提供了一个函数,当调用该函数时,它将阻塞您的线程,直到OS向其发送事件为止。因此,是的,即使是非阻塞I / O也会阻塞您的线程。这里的关键是阻塞I / O将在多个位置阻塞您的线程,但非阻塞I / O仅在一个位置(您等待事件的位置)阻塞您的线程。
请查看我对另一个问题的回答,以获取有关此类API在C /C++级别如何工作的更具体示例:我知道回调函数异步运行,但是为什么呢 ?
对于按钮单击和鼠标移动OS等GUI事件,只需跟踪鼠标和键盘中断,然后将其转换为UI事件即可。这样可以释放您需要知道按钮,窗口,图标等位置的软件表格。
这允许您做的是以面向事件的方式设计程序。这类似于中断使OS设计人员实现多任务处理的方式。实际上,异步I / O对框架而言是对OS的中断。它允许javascript花费正好0%的CPU时间来处理(等待)I /O。这就是使异步代码快速的原因-并不是真的更快,但不会浪费时间等待。