异步编程如何在单线程编程模型中工作?
Posted
技术标签:
【中文标题】异步编程如何在单线程编程模型中工作?【英文标题】:How does Asynchronous programming work in a single threaded programming model? 【发布时间】:2012-02-17 10:38:22 【问题描述】:我在浏览node.js
的细节时才知道,它支持异步编程,尽管它本质上提供了一个单线程模型。
在这种情况下如何处理异步编程?是不是就像runtime自己创建和管理线程,但是程序员不能显式创建线程?如果有人能指出一些资源来了解这一点,那就太好了。
【问题讨论】:
【参考方案1】:Ryan 说得最好:同步/异步与单/多线程正交。对于单线程和多线程情况,有一个主事件循环使用Reactor Pattern 调用注册的回调。对于单线程情况,回调在主线程上按顺序调用。对于多线程情况,它们在单独的线程上调用(通常使用线程池)。这实际上是一个有多少争用的问题:如果所有请求都需要同步访问单个数据结构(例如订阅者列表),那么拥有多线程的好处可能会减少。这取决于问题。
就实现而言,如果框架是单线程的,那么它很可能使用poll/select 系统调用,即操作系统正在触发异步事件。
【讨论】:
【参考方案2】:现在跟我说吧:异步编程并不一定意味着多线程。
javascript 是单线程运行时 - 您根本无法在 JS 中创建新线程,因为语言/运行时不支持它。
Frank 说得对(虽然很迟钝) 用英语:当事情进入您的应用程序时,有一个主事件循环来处理。因此,“处理这个 HTTP 请求”将被添加到事件队列中,然后在适当的时候由事件循环处理。
当您调用异步操作(例如 mysql 数据库查询)时,node.js 会向 mysql 发送“嘿,执行此查询”。由于这个查询需要一些时间(毫秒),node.js 使用 MySQL 异步库执行查询 - 回到事件循环并在等待 mysql 返回给我们的同时做 其他事情 .就像处理那个 HTTP 请求一样。
编辑:相比之下,node.js 可以简单地等待(什么都不做)让 mysql 回到它。这称为同步调用。想象一家餐厅,您的服务员将您的订单提交给厨师,然后在厨师做饭时坐下并转动他/她的拇指。在餐厅中,比如在 node.js 程序中,这种行为是愚蠢的——你有其他顾客饿了,需要被服务。因此,您希望尽可能异步,以确保一个服务员(或 node.js 进程)为尽可能多的人提供服务。
编辑完成
Node.js 使用 C 库与 mysql 通信,因此从技术上讲,这些 C 库可以产生线程,但在 Javascript 中,您不能对线程进行任何操作。
【讨论】:
更准确。 “Node.js 通过异步 API 与 mysql 通信。异步 API 的实现是用 C 语言实现的,该实现可能只是通过线程池运行同步 API”。异步 API 可能在内部使用线程池这一事实是您不关心的低级细节。 啊,所以mysql在不同的线程中运行,然后在完成后将事件添加回JS。如果我想制作自己的异步模块,我可以使用 node 中的子进程来达到相同的效果。 我认为这里最好避免使用“线程”这个词——人们听到它时会跳出错误的结论。异步调用可以使用线程,或者 fork 进程,或者做任何事情;重要的是,事件循环后面可能会发生回调或事件。 餐厅-服务员-厨师的例子真的很到位,+1。【参考方案3】:重申服务员/厨师的类比:
你的程序是一个服务员(“你”),而 JavaScript 运行时是一个厨房,里面满是做你要求的事情的厨师。
服务员和厨房之间的接口由队列调解,因此请求不会在容量过剩的情况下丢失。
所以你的程序被分配了一个执行线程。您一次只能等一张桌子。每次您想卸载一些工作(例如制作食物/发出网络请求)时,您都会跑到厨房并将订单固定到板(队列)上,以便厨师(运行时)在他们有空闲容量时拿起.厨师会在订单准备好时通知您(他们会回电给您)。与此同时,你去等另一张桌子(你没有被厨房挡住)。
所以接受的答案具有误导性。 JavaScript 运行时定义为多线程,因为 I/O 不会阻塞您的 JavaScript 程序。作为服务员,您可以在厨房做饭的同时继续为顾客服务。这涉及至少两个执行线程。现实情况是,运行时将在幕后维护多个执行线程,以便有效地为与您的脚本直接对应的单个线程提供服务。
按照设计,只有一个执行线程被分配给 JavaScript 程序的同步运行。这是一件好事,因为它使您的程序比必须自己处理多个执行线程更容易推理。不用担心:您的 JavaScript 程序仍然会变得非常复杂!
【讨论】:
以上是关于异步编程如何在单线程编程模型中工作?的主要内容,如果未能解决你的问题,请参考以下文章