进程

一个应用程序,总是通过操作系统启动的,当操作系统启动一个应用程序时,会给其分配一个进程

一个进程拥有独立的、可伸缩的内存空间,原则上不受其他进程干扰

进程之间是可以通信的,只要两个进程双方遵守一定的协议,比如ipc

CPU在不同的进程之间切换执行

虽然一个应用程序在启动时只有一个进程,但它在运行的过程中,可以开启新的进程,进程之间仍然保持相对独立

如果一个进程是直接由操作系统开启,则它叫做主进程

如果一个进程B是由进程A开启,则A是B的父进程,B是A的子进程,子进程会继承父进程的一些信息,但仍然保持相对独立

  1. // nodejs 中开启子进程
  2. const childProcess = require("child_process"); // 导入内置模块
  3. childProcess.exec(在子进程运行的命令, (err, out, stdErr) => {
  4. // 回调函数中可以获取子进程的标准输出,这种数据交互是通过IPC完成的,nodejs已经帮你完成了处理
  5. // err:开启进程过程中发生的错误
  6. // out: 子进程输出的正常内容
  7. // stdErr: 子进程输出的错误内容
  8. // 子进程发生任何的错误,绝不会影响到父进程,它们的内存空间是完全隔离的
  9. });
  10. // 过去,nodejs没有提供给用户创建线程的接口,只能使用进程的方式
  11. // 过去,nodejs还提供了cluster模块,通过另一种模式来创建进程
  12. // 现在,nodejs已经提供了线程模块,对进程的操作已经很少使用了

线程

操作系统启动一个进程(无论是主进程,还是子进程),都会自动为它分配一个线程,称之为主线程

程序一定在线程上运行!!

主线程在运行的过程中,可以创建多个线程,这些线程称之为子线程

当操作系统命令CPU去执行一个进程时,实际上,是在该进程的多个线程中切换执行

线程和进程很相似,它们都是独立运行,最大的区别在于:线程的内存空间没有隔离,共享进程的内存空间,线程之间的数据不用遵守任何协议,可以随意使用

什么时候要使用线程?

使用线程的主要目的,是为了充分使用多核cpu。线程执行过程中,尽量的不要阻塞。

最理想的线程效果:

  1. 线程数等于cpu的核数
  2. 线程永不阻塞
    1. 没有io
    2. 只存在大量运算
  3. 线程相对独立,几乎不使用共享数据

线程一般处理cpu密集型操作(运算操作),而io密集型操作不适合使用线程,而适合使用异步

为了避免线程执行过程中共享数据产生的麻烦,nodejs使用独特的线程机制来尽力规避:

  1. // 创建子线程的父线程
  2. const { Worker } = require("worker_threads");
  3. const worker = new Worker(线程执行的入口文件, {
  4. workerData: 开启线程时向其传递的数据,
  5. }); // worker是子线程实例
  6. // 通过EventEmitter监听子线程的事件
  7. worker.on("exit", () => {
  8. // 当子线程退出时运行的事件
  9. });
  10. worker.on("message", (msg) => {
  11. // 收到子线程发送的消息时运行的事件
  12. });
  13. worker.postMessage(任意消息); // 父线程向子线程发送任意消息
  14. worker.terminate(); // 退出子线程
  1. const {
  2. isMainThread, // 是否是主线程
  3. parentPort, // 用于与父线程通信的端口
  4. workerData, // 获取线程启动时传递的数据
  5. threadId, // 获取线程的唯一编号
  6. } = require("worker_threads");
  7. parentPort.on("message", (msg) => {
  8. // 当收到父线程发送的消息时,触发的事件
  9. });
  10. parentPort.postMessage(workerData); // 向父线程发送消息

参考文章:https://juejin.cn/post/6844903908385488903