异步编程如何在单线程编程模型中工作?

我浏览了 node.js的详细信息,了解到,它支持异步编程,尽管本质上它提供了一个单线程模型。

在这种情况下如何处理异步编程?是不是像运行时本身创建和管理线程,但程序员不能显式地创建线程?如果有人能给我提供一些资源来了解这个,那就太好了。

20581 次浏览

Ryan 说得最好: sync/sync 与单线程/多线程是正交的。对于单线程和多线程情况,有一个主事件循环,它使用 反应堆模式调用已注册的回调。对于单线程情况,回调将在主线程上顺序调用。对于多线程情况,它们在单独的线程上调用(通常使用线程池)。这实际上是一个有多少争用的问题: 如果所有请求都需要同步访问单个数据结构(比如订阅者列表) ,那么拥有多线程的好处可能会减少。这取决于问题。

就实现而言,如果一个框架是单线程的,那么它可能使用 民意调查/选择系统调用,即操作系统触发异步事件。

现在跟我说: 异步编程并不一定意味着多线程。

Javascript 是一个单线程运行时——你不能在 JS 中创建新的线程,因为语言/运行时不支持它。

弗兰克用英语说得很正确(虽然有点含糊) : 有一个主事件循环,当事件进入你的应用程序时会进行处理。因此,“处理这个 HTTP 请求”将被添加到事件队列中,然后在适当的时候由事件循环处理。

当您调用一个异步操作(例如 mysql db 查询)时,node.js 向 mysql 发送“ hey,execute this query”。由于这个查询需要一些时间(毫秒) ,node.js 使用 MySQL 异步库执行查询——返回到事件循环并在那里执行 别的东西,同时等待 MySQL 返回给我们。比如处理 HTTP 请求。

编辑 : 相比之下,node.js 可以只是等待(什么也不做) ,等待 mysql 返回到它。这就是所谓的同步调用。设想一家餐厅,你的服务员把你点的菜交给厨师,然后坐下来,在厨师做饭的时候玩弄他/她的拇指。在餐馆里,就像在 node.js 程序中一样,这种行为是愚蠢的——你有其他饥饿的顾客需要服务。因此,您希望尽可能地保持异步,以确保一个侍者(或 node.js 进程)为尽可能多的人提供服务。

编辑完毕

Js 使用 C 库与 mysql 通信,所以从技术上讲,这些 C 库可以产生线程,但是在 Javascript 中,你不能对线程做任何事情。

重申一下服务生/厨师的类比:

你的程序是一个服务员(“你”) ,JavaScript 运行时是一个厨房,里面的厨师都在做你要求的事情。

服务员和厨房之间的接口是由队列调节的,因此在容量过大的情况下请求不会丢失。

所以你的程序被分配了一个执行线程。一次只能等一张桌子。每次你想卸下一些工作(比如制作食物/发出网络请求) ,你跑到厨房,把订单钉在一个板子上(队列) ,让厨师(运行时)在他们有空余容量的时候来取。厨师会让你知道什么时候可以点菜(他们会给你回电话)。与此同时,你去等另一张桌子(你不会被厨房挡住)。

因此,公认的答案具有误导性。JavaScript 运行时在定义上是多线程的,因为 I/O 不会阻塞 JavaScript 程序。作为一名服务员,你可以在厨房做饭的时候继续为顾客服务。它至少涉及两个执行线程。实际情况是,运行时将在幕后维护多个执行线程,以便有效地为与脚本直接对应的单个线程提供服务。

根据设计,只有一个执行线程被分配给 JavaScript 程序的同步运行。这是一件好事,因为它使您的程序更容易推理,而不必自己处理多个执行线程。不要担心: 您的 JavaScript 程序仍然可以变得非常复杂!