我知道 node.js 是一个单线程、异步、非阻塞 i/o。我已经阅读了很多关于这方面的内容。例如,PHP 每个请求使用一个线程,但节点只使用一个线程,就像那样。
假设有 3 个请求 a、b、c 同时到达 node.js 服务器。其中三个请求需要大型阻塞操作,例如它们都想读取同一个大文件。
那么请求如何排队,阻塞操作将按什么顺序执行,响应按什么顺序分派?当然使用多少线程?
请告诉我三个请求从请求到响应的顺序。
我知道 node.js 是一个单线程、异步、非阻塞 i/o。我已经阅读了很多关于这方面的内容。例如,PHP 每个请求使用一个线程,但节点只使用一个线程,就像那样。
假设有 3 个请求 a、b、c 同时到达 node.js 服务器。其中三个请求需要大型阻塞操作,例如它们都想读取同一个大文件。
那么请求如何排队,阻塞操作将按什么顺序执行,响应按什么顺序分派?当然使用多少线程?
请告诉我三个请求从请求到响应的顺序。
以下是您的三个请求的一系列事件的描述:
因此,即使只有一个请求实际上同时执行,多个请求也可以同时“进行中”或“进行中”。这有时被称为协作多任务处理,而不是具有多个本地线程的“抢先式”多任务处理,系统可以随时在线程之间自由切换,Javascript 的给定线程运行直到它返回到系统,然后,只有这样,另一段 Javascript 才能开始运行。因为一段 Javascript 可以发起非阻塞异步操作,所以 Javascript 的线程可以在异步操作仍然挂起时返回系统(使其他 Javascript 段运行)。当这些操作完成时,
单线程
这里的关键点是给定的 Javascript 线程将一直运行,直到它返回系统。如果在执行过程中启动了一些异步操作(比如文件 I/O 或网络),那么当这些事件完成时,它们会将一个事件放入事件队列中,当 JS 引擎完成运行之前的任何事件时它,该事件将得到服务,并将导致回调被调用,并且该回调将轮到执行。
与多线程模型相比,这种单线程特性极大地简化了并发处理方式。在一个完全多线程的环境中,每个请求都启动自己的线程,然后任何希望共享的数据,即使是简单的变量也会受到竞争条件的影响,并且必须使用互斥锁保护,然后任何人才能读取它。
在 Javascript 中,因为没有并发执行多个请求,所以简单的共享变量访问不需要互斥锁。此时一段 Javascript 正在读取一个变量,根据定义,此时没有其他 Javascript 正在运行(单线程)。
Node.js 确实使用线程
一个值得注意的技术区别是,只有 Javascript 的执行是单线程的。node.js 内部确实在某些事情上使用线程本身。例如,异步文件 I/O 实际上使用本机线程。网络 I/O 实际上并不使用线程(它使用本机事件驱动的网络)。
但是,在 node.js 内部使用线程不会直接影响 Javascript 的执行。一次仍然只有一个 Javascript 线程在执行。
比赛条件
在启动异步操作时,仍然可能存在正在修改的状态的竞争条件,但这种情况比在多线程环境中少见,而且更容易识别和保护这些情况。作为可能存在的竞争条件的示例,我有一个简单的服务器,它使用间隔计时器每 10 秒从几个温度探测器中读取读数。它从所有这些温度读数中收集数据,并且每小时将这些数据写入磁盘。它使用异步 I/O 将数据写入磁盘。但是,由于许多不同的异步文件 I/O 操作用于将数据写入磁盘,因此间隔计时器可能会在其中一些异步文件 I/O 操作之间触发,从而导致服务器所在的数据写入磁盘的中间要修改。这很糟糕,可能会导致写入不一致的数据。在一个简单的世界中,可以通过在开始将数据写入磁盘之前复制所有数据来避免这种情况,因此如果在将数据写入磁盘时出现新的温度读数,则副本不会受到影响并且代码仍会将一组一致的数据写入磁盘。但是,在这个服务器的情况下,数据可能很大而服务器上的内存很小(它是一个 Raspberry Pi 服务器),因此在内存中复制所有数据是不切实际的。副本不会受到影响,代码仍会将一组一致的数据写入磁盘。但是,在这个服务器的情况下,数据可能很大而服务器上的内存很小(它是一个 Raspberry Pi 服务器),因此在内存中复制所有数据是不切实际的。副本不会受到影响,代码仍会将一组一致的数据写入磁盘。但是,在这个服务器的情况下,数据可能很大而服务器上的内存很小(它是一个 Raspberry Pi 服务器),因此在内存中复制所有数据是不切实际的。
因此,通过在数据正在写入磁盘的过程中设置一个标志,然后在数据完成写入磁盘时清除该标志来解决问题。如果在设置此标志时触发间隔计时器,则新数据将放入单独的队列中,并且不会修改正在写入磁盘的核心数据。数据写入磁盘完成后,它会检查队列,然后将在其中找到的任何温度数据添加到内存中的温度数据中。正在写入磁盘的过程中的内容的完整性得以保留。每当遇到此“竞争条件”并且数据因此而排队时,我的服务器都会记录一个事件。而且,你瞧,它确实每隔一段时间就会发生一次,并且保持数据完整性的代码有效。