【发布时间】:2016-04-08 08:28:18
【问题描述】:
我浏览了一些关于 Node.js 和 Event Loop 的介绍性文章,但有一点不清楚 - 如果有多个并发请求,那么响应是否总是按照发出请求的顺序排列?假设如果 20 个请求同时完成,那么第 20 个响应是否必须等待其他 19 个被清除(响应回客户端)?
更新:我想知道这是否类似于多个 setTimeouts 排队的方式?
【问题讨论】:
标签: node.js concurrency
我浏览了一些关于 Node.js 和 Event Loop 的介绍性文章,但有一点不清楚 - 如果有多个并发请求,那么响应是否总是按照发出请求的顺序排列?假设如果 20 个请求同时完成,那么第 20 个响应是否必须等待其他 19 个被清除(响应回客户端)?
更新:我想知道这是否类似于多个 setTimeouts 排队的方式?
【问题讨论】:
标签: node.js concurrency
node.js 作为单线程运行 Javascript。因此,在任何给定时间,只有一段 Javascript 正在运行。
但是,几乎所有 I/O(例如网络、文件访问等)都是异步且非阻塞的。因此,如果在很短的时间内向您的服务器发出 20 个请求,到达服务器的第一个请求将开始执行它的请求处理程序,其他请求将排队。但是,一旦第一个请求遇到异步操作(例如从本地文件系统读取),该请求将在发生非阻塞异步 I/O 时暂停,并且行中的下一个请求将开始运行.
然后,第二个请求将一直运行,直到它完成或直到它也遇到一个异步 I/O。当第二个请求在异步 I/O 上等待时,另一个请求将开始运行。系统调度程序将确定下一个操作是完成第一个请求的异步 I/O 请求,还是启动队列中等待的第三个请求。
各种请求将继续以这种方式进行,直到全部完成。多个请求可能同时“进行中”(意味着它们已经开始,但尚未完成),但在任何给定时刻只有一个实际执行代码。
这有时被称为合作任务。不同请求之间没有抢先式多任务处理,每个请求都会自动获取主机 CPU 的时间片。但是,只要一个请求遇到异步 I/O 操作,就会告诉调度程序等待运行的其他请求可以运行。
这一切都由 node.js 中的事件队列管理。一段 Javascript 一直运行直到完成。如果它发出一个异步 I/O 请求然后完成,那么另一段也在等待运行的 Javascript 可以开始运行。完成后,JS 引擎将下一项从事件队列中拉出并运行。这可能是一个新的传入请求,也可能是对某个其他请求的某个异步 I/O 操作的完成。
这种系统的优点是:
它的可伸缩性非常好,尤其是对于 I/O 绑定的服务器操作,因为您可以只使用一个 Javascript 线程同时“进行中”许多请求。协作任务非常轻量和快速。
编写这样的系统需要注意的“竞争条件”要少得多,因为实际上没有两段 Javascript 会同时运行。这意味着您可以经常在请求之间共享状态,而无需使用互斥锁(就像在多线程环境中一样)。由于线程安全的错误通常很难避免和测试,因此消除这些类型的错误是一个主要优势。
协作模型在概念上很简单,更易于学习和安全编程。
这种系统的缺点是:
它不会在受 CPU 限制的任务之间共享 CPU。具有大量 CPU 密集型计算的 node.js 程序员通常必须使用集群或子进程来处理繁重的 CPU 计算,以免使主请求处理 Javascript 线程的工作负担过重,并使其过于无响应.
需要进程集群以最大限度地利用多个处理器,然后必须在这些进程之间共享任何共享数据。人们经常使用 Redis 等内存数据库在进程之间共享数据。
你不能随便启动另一个 Javascript 线程来做某事。
【讨论】:
fs.readFile() 是异步的。 fs.readFileSync() 是同步的。根据函数的接口或文档,这通常是显而易见的,但为了正确使用函数,您必须了解这一点。