nodejs支持多线程吗(Nodejs构建Cluster集群多线程Workerthreads)
前言
前两天我们介绍了使用 Nodejs 中的 child_process 模块创建多个子进程 ,同时利用进程间通信的API构建了一个集群式的Web服务器 。实际上 ,你可以通过 cluster 模块更方便的完成这一操作 。
但是 ,cluster 创建的进程之间无法共享内存 ,通信必须使用 JSON 格式 ,有一定的局限性和性能问题 。如果你不想要进程隔离 ,可以使用 worker_thread 模块 ,它允许在一个 Node.js 实例中运行多个应用程序线程 。相比创建多个进程更轻量 ,并且可以共享内存 。
进程间通过传输 ArrayBuffer 实例或共享 SharedArrayBuffer 实例来做到这一点 ,对数据格式没有太多要求 。但是要注意 ,数据中不能包含函数 。
Cluster 多进程
我们可以使用 cluster 模块提供的API重构昨天的案例:
子进程依旧使用昨天的代码:
执行 node master.js,会得到与昨天利用 child_process 模块创建子进程集群相同的效果 。
同样 ,你可以使用官方推荐的写法 ,利用 cluster.isPrimary 和 cluster.isWorker 来判断当前进程是否为主进程:
实现原理
事实上,cluster 模块就是将 child_process 和 net 模块的API组合起来实现的 。cluster启动时 ,进程会在内部启动TCP服务器 。而在调用 cluster.fork() 复制子进程时 ,会将这个TCP服务器端 Socket 的句柄发送给工作进程 。如果进程是通过 cluster.fork() 复制出来的 ,那么它的环境变量里就存在 NODE_UNIQUE_ID 。如果工作进程中存在 listen() 侦听网络端口的调用 ,它将拿到该句柄 ,再通过 SO_REUSEADDR 端口重用 ,从而实现多个子进程共享端口。对于正常方式启动的进程 ,则不存在句柄共享和传递等过程 。
在 cluster 内部隐式创建TCP服务器的方式对使用者是透明的 ,你不需要自己手动去实现句柄的传递 ,但也正是因此 ,它无法像使用 child_process 那样灵活 。在 child_process 中你可以自行控制句柄的传送 ,因此可以灵活地控制工作进程 ,甚至控制多组工作进程。
cluster事件
Event: disconnect 主进程和工作进程之间IPC通道断开后会触发该事件 。 Event: exit 有工作进程退出时触发该事件 。 Event: fork 复制一个工作进程后触发该事件 。 Event: listening 工作进程中调用 listen() 后,发送该消息给主进程 ,主进程收到后 ,触发该事件 。 Event: message Event: online fork好一个工作进程后,工作进程主动发送该消息给主进程 ,主进程收到消息后 ,触发该事件 。 Event: setup .setupPrimary() 方法执行后触发? 这些事件大多跟 child_process 模块的事件相关 ,在进程间消息传递的基础上完成的封装 。
使用 Node 构建集群能够充分利用多核CPU的计算性能 ,而 child_process 模块的进程间通信和多种事件能够极大提升Node的稳定性 。但进程间无法共享资源 ,进程间通信有局限性和性能问题 。此时就需要引入更轻量级的线程了 。
Worker threads多线程
V8 多线程模型
众所周知 ,JavaScript 在运行时是单线程的 。但 JavaScript 的 Runtime V8 引擎却不是单线程的 。大致包括以下几个线程:
JavaScript 主线程:编译 、执行代码 。 编译线程:当主线程在执行时 ,编译线程可以优化代码。 Profiler 线程:记录方法耗时的线程 。 其它线程:比如支持并行 GC 的多线程 。 libuv线程池 ,默认四个线程 ,全局共享 ,可以将异步操作和计算密集任务交给它执行。对于 Node 来说 ,crypto 这种 CPU 密集 和 fs 这种 I/O 密集的任务是在 libuv线程池 中进行的 。其执行模型是单独创建一个进程 ,在这个进程中同步执行任务,然后将结果返回到 Event Loop 中 ,Event Loop 可以通过回调函数获取并使用结果 。
使用非阻塞方法 ,长耗时的方法不会阻塞主进程之后的代码,只需告诉 Worker Pool 去执行该命令 ,并将结果返回给预先设置好的回调函数 ,在计算完成时触发即可 。
? 由于 Worker Pool 运行在 libuv线程池 中 ,主线程的 Event Loop 不会被阻塞 。能够充分利用 CPU 资源 。
多线程支持
Node v10.5.0 提供了 Worker threads 模块 ,开始支持多线程编程 。在创建出的每个工作线程中 ,都会包含 V8 和 libuv ,即都包含Event Loop:
你可以通过下面这段简单的代码来体验一下:
我们在主线程中调用new方法创建了一个子线程 ,子线程执行完自动销毁 。最后执行结果如下:
? 合理使用子线程 ,你能充分调用和分配资源 。对于有计算密集型需求的应用 ,这是一个重要的优化手段 。另外 ,由于频繁地创建 、销毁一个线程的开销很大 ,你可以创建线程池来解决这个问题 。
总结
通过构建集群 ,你能够充分调用CPU资源,赋予Node更强劲的性能 。而利用多线程模型 ,将长耗时的任务交由子线程来处理 ,你能合理分配程序运行资源 。
目前为止,我们介绍完了 Node 的网络 、IO 、进程模块 ,还剩下异步编程和Event Loop两个重点。另外 ,今天在看 Node 文档时发现 Node v19 刚刚发布了 ,v18 即将成为稳定版
以上就是Nodejs 构建Cluster集群多线程Worker threads的详细内容 ,更多关于Nodejs 构建Cluster多线程的资料请关注本站其它相关文章!
创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!