Javascript的运行,我们知道是单线程的,目的是为了解决内存冲突等的问题,同时单线程的设计也方便问题的查找和解决,在浏览器端,单线程基本都可以满足,但是在NodeJS服务端的话,如果有大规模的计算或者耗时业务流程就会堵塞后面的请求,比如有一个客户端请求,需要从数据库里面取出数据,然后进行各种计算,一般计算过程都是用JS写的,如果这个计算过程很耗时(假如需要10s),就会导致后面的请求得不到响应,之前我们的做法就是N-API写一个C++的addon去开辟新线程去计算或者直接用模块child-process开辟一个新的js进程去计算,等返回之后再用主进程的JS去处理。
worker_threads是NodeJS team开发的真线程模块,可以做到真线程的原因当然是v8-isolate,v8-isolate是Chromium runtime 的一个独立的实例,我们的worker是完全独立于其他worker运行的,有独立的context, 也就是有独立的v8和event loop,与模块child_process和cluster的区别是能share memory,某种程度上可以克服performance和memory的问题。
子线程的执行过程:
1. 创建独立的v8 isolate,并且assgin给worker, 这使worker有独立的context。
2. libuv初始化,这让worker有独立的event loop。
3. worker开始真正的执行,event loop开始运行。
4. worker调用c++,读取主线程发过来的workerData。
5. worker执行js 文件或者code。作为独立线程运行。
parent线程创建子线程时的初始化过程:
1. 通过worker_threads创建一个worker。
2. 调用c++创建一个C++worker 对象,实际上是个空对象。
3. 给C++ worker对象创建线程ID。
4. C++ worker对象创建initialisation message channel,
5. 一个public message channel 的JS对象被创建,用来父线程和子线程通过postMessage函数互相通信。
6. 父线程调用C++发送workerData对象到c++ message channel,该对象用来传输给子线程初始化的时候调用。
下面的几个参考网页:
为什么需要多线程
NodeJS网站