Sid*_*rth 17 nonblocking single-threaded node.js
我知道node.js是一个单线程,异步,非阻塞的i/o.我已经阅读了很多相关内容.例如,PHP每个请求使用一个线程,但节点只使用一个线程,就像那样.
假设在node.js服务器上有三个请求a,b,c同时到达.其中三个请求需要大量阻塞操作,例如,他们都想读取相同的大文件.
那么请求如何排队,执行阻塞操作的顺序以及调度响应的顺序是什么?当然使用了多少线程?
请告诉我三个请求的请求到响应的顺序.
jfr*_*d00 42
以下是对三个请求的一系列事件的描述:
因此,即使只有一个请求实际上同时执行,多个请求可以同时"在进行中"或"在飞行中".这有时被称为协作多任务,而不是"先发制人"的多任务处理,而不是任何时刻系统可以在线程之间自由切换的多个本机线程,Javascript的给定线程运行直到它返回到系统然后,只有这样,另一块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服务器),因此制作所有数据的内存副本是不切实际的.
因此,通过在数据处于写入磁盘的过程中设置标志然后在数据写入磁盘时清除标志来解决问题.如果在设置此标志时间隔计时器触发,则新数据将被放入单独的队列中,并且不会修改正在写入磁盘的核心数据.当数据写入磁盘时,它会检查队列,然后将它找到的任何温度数据添加到内存温度数据中.保留了写入磁盘的过程的完整性.我的服务器会在遇到此"竞争条件"并且数据因此而排队时记录事件.并且,瞧,它确实每隔一段时间发生一次,并且保存数据完整性的代码可以工作.
| 归档时间: |
|
| 查看次数: |
6977 次 |
| 最近记录: |