Heim > Web-Frontend > js-Tutorial > Hauptteil

Eine eingehende Analyse der Prozesse und Threads in Node

青灯夜游
Freigeben: 2022-12-27 19:17:33
nach vorne
1733 Leute haben es durchsucht

Threads und Prozesse sind die Grundkonzepte von Computerbetriebssystemen und unter Programmierern häufig verwendete Wörter. Wie verstehen Sie sie? Was ist mit Prozessen und Threads in Node.js? Der folgende Artikel vermittelt Ihnen ein detailliertes Verständnis der Prozesse und Threads in Node. Es hat einen gewissen Referenzwert. Freunde in Not können sich darauf beziehen. Ich hoffe, es wird für alle hilfreich sein.

Eine eingehende Analyse der Prozesse und Threads in Node

1. Prozesse und Threads

1.1. Professionelle Textdefinition

  • Prozess (Prozess), ein Prozess ist ein Programm im Computer, das eine Aktivität für eine bestimmte Datensammlung ausführt, und ist ein Systemressource Die Grundeinheit der Zuweisung und Planung ist die Grundlage der Betriebssystemstruktur. Der Prozess ist der Thread-Container. [Verwandte Tutorial-Empfehlungen: nodejs-Video-Tutorial, Programmierlehre]
  • Thread (Thread), der Thread ist die kleinste Einheit, die das Betriebssystem zur Berechnungsplanung durchführen kann. Er ist im Prozess enthalten und die eigentliche Betriebseinheit dabei.

1.2. Populäres Verständnis

Die obige Beschreibung ist nach dem Lesen möglicherweise nicht förderlich und trägt nicht zum Verständnis und zur Erinnerung bei. Nehmen wir also ein einfaches Beispiel:

Angenommen, Sie sind jemand an einer bestimmten Expresszustellstelle. Zunächst gibt es in dem Gebiet, für das diese Stelle zuständig ist, nicht viele Einwohner, und Sie sind der Einzige, der die Pakete abholt. Nachdem Sie das Paket bei Zhang San abgeliefert haben und es dann bei Li Si abgeholt haben, müssen die Dinge einzeln erledigt werden. Dies wird als „einzelner Thread“ bezeichnet und alle Arbeiten müssen in der richtigen Reihenfolge ausgeführt werden. Später gab es mehr Bewohner in diesem Bereich, und der Standort hat diesem Bereich mehrere Leute und einen Teamleiter zugewiesen. Sie können mehr Bewohner betreuen. Dies wird als Multi-Threading
bezeichnet, und der Teamleiter ist Hauptthread. Jeder Typ ist ein Thread. Die von Express-Lieferstellen verwendeten Tools wie Einkaufswagen werden von der Website bereitgestellt und können von allen genutzt werden, nicht nur von einer Person. Dies wird als Multithread-Ressourcenfreigabe bezeichnet.
Derzeit gibt es nur einen Site-Warenkorb und jeder muss ihn verwenden. Dies wird als Konflikt
bezeichnet. Es gibt viele Möglichkeiten, das Problem zu lösen, z. B. das Warten in der Schlange oder das Warten auf Benachrichtigungen, wenn andere Leute fertig sind. Dies wird als „Thread-Synchronisierung“ bezeichnet.

Der Hauptsitz hat viele Standorte und das Betriebsmodell jedes Standorts ist fast genau das gleiche. Dies wird als

MultiprozessEine eingehende Analyse der Prozesse und Threads in Node bezeichnet. Der Hauptsitz wird als

Hauptprozess

bezeichnet, und jeder Standort wird als Unterprozess bezeichnet. Zwischen der Zentrale und dem Standort sowie zwischen den einzelnen Standorten sind die Wagen unabhängig voneinander und können nicht gemischt werden. Dies wird als „keine gemeinsame Nutzung von Ressourcen zwischen Prozessen“ bezeichnet. Jeder Standort kann über Telefonanrufe usw. miteinander kommunizieren. Dies wird als „Pipeline“ bezeichnet. Es gibt andere Möglichkeiten der Zusammenarbeit zwischen Standorten, um die Erledigung größerer Rechenaufgaben zu erleichtern, was als „Interprozesssynchronisation“ bezeichnet wird. Sie können auch einen Blick auf Ruan Yifengs Eine einfache Erklärung von Prozessen und Threads
werfen. 2. Prozesse und Threads in Node.jsNode.js ist ein Single-Thread-Dienst mit ereignisgesteuerten und nicht blockierenden E/A-Modellsprachenfunktionen, die Node.js effizient und leichtgewichtig machen. Der Vorteil besteht darin, dass häufige Thread-Wechsel und Ressourcenkonflikte vermieden werden. Es eignet sich gut für E/A-intensive Vorgänge (das zugrunde liegende Modul libuv führt Multitasking aus, indem es die vom Betriebssystem bereitgestellten asynchronen E/A-Funktionen über Multithreads aufruft). , aber für Node.js auf der Serverseite müssen möglicherweise Hunderte von Anforderungen pro Sekunde verarbeitet werden. Da es sich um einen Single-Thread-Modus handelt, führt dies unweigerlich zu Blockierungen.

2.1, Node.js-Blockierung

Wir verwenden Koa, um einfach einen Webdienst zu erstellen und verwenden die Fibonacci-Sequenzmethode, um Node.js bei der Verarbeitung CPU-intensiver Rechenaufgaben zu simulieren:

Fibonacci Eine Zahlenfolge, auch bekannt als Goldene-Schnitt-Sequenz. Diese Sequenz beginnt mit dem dritten Element und jedes Element ist gleich der Summe der beiden vorherigen Elemente: 0, 1, 1, 2, 3, 5, 8, 13, 21, ... .

// app.js
const Koa = require('koa')
const router = require('koa-router')()
const app = new Koa()

// 用来测试是否被阻塞
router.get('/test', (ctx) => {
    ctx.body = {
        pid: process.pid,
        msg: 'Hello World'
    }
})
router.get('/fibo', (ctx) => {
    const { num = 38 } = ctx.query
    const start = Date.now()
    // 斐波那契数列
    const fibo = (n) => {
        return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1
    }
    fibo(num)

    ctx.body = {
        pid: process.pid,
        duration: Date.now() - start
    }
})

app.use(router.routes())
app.listen(9000, () => {
    console.log('Server is running on 9000')
})
Nach dem Login kopieren

Ausführung Starten Sie den Dienst und verwenden Sie Postman, um die Anfrage zu senden. Mit anderen Worten: Da eine CPU-intensive Rechenaufgabe ausgeführt wurde, wurde der Node.js-Hauptthread blockiert als sechshundert Millisekunden. Wenn mehr Anfragen gleichzeitig verarbeitet werden oder die Berechnungsaufgabe komplexer ist, werden alle nachfolgenden Anfragen verzögert.

Erstellen wir eine neue axios.js, um das Senden mehrerer Anfragen zu simulieren. Ändern Sie zu diesem Zeitpunkt die Anzahl der Fibo-Berechnungen in app.js auf 43, um komplexere Rechenaufgaben zu simulieren:

// axios.js
const axios = require('axios')

const start = Date.now()
const fn = (url) => {
    axios.get(`http://127.0.0.1:9000/${ url }`).then((res) => {
        console.log(res.data, `耗时: ${ Date.now() - start }ms`)
    })
}

fn('test')
fn('fibo?num=43')
fn('test')
Nach dem Login kopieren

可以看到,当请求需要执行 CPU 密集型的计算任务时,后续的请求都被阻塞等待,这类请求一多,服务基本就阻塞卡死了。对于这种不足,Node.js 一直在弥补。

2.2、master-worker

master-worker 模式是一种并行模式,核心思想是:系统有两个及以上的进程或线程协同工作时,master 负责接收和分配并整合任务,worker 负责处理任务。

Eine eingehende Analyse der Prozesse und Threads in Node

2.3、多线程

线程是 CPU 调度的一个基本单位,只能同时执行一个线程的任务,同一个线程也只能被一个 CPU 调用。如果使用的是多核 CPU,那么将无法充分利用 CPU 的性能。

多线程带给我们灵活的编程方式,但是需要学习更多的 Api 知识,在编写更多代码的同时也存在着更多的风险,线程的切换和锁也会增加系统资源的开销。

worker_threads 是 Node.js 提供的一种多线程 Api。对于执行 CPU 密集型的计算任务很有用,对 I/O 密集型的操作帮助不大,因为 Node.js 内置的异步 I/O 操作比 worker_threads 更高效。worker_threads 中的 Worker,parentPort 主要用于子线程和主线程的消息交互。

将 app.js 稍微改动下,将 CPU 密集型的计算任务交给子线程计算:

// app.js
const Koa = require('koa')
const router = require('koa-router')()
const { Worker } = require('worker_threads')
const app = new Koa()

// 用来测试是否被阻塞
router.get('/test', (ctx) => {
    ctx.body = {
        pid: process.pid,
        msg: 'Hello World'
    }
})
router.get('/fibo', async (ctx) => {
    const { num = 38 } = ctx.query
    ctx.body = await asyncFibo(num)
})

const asyncFibo = (num) => {
    return new Promise((resolve, reject) => {
        // 创建 worker 线程并传递数据
        const worker = new Worker('./fibo.js', { workerData: { num } })
        // 主线程监听子线程发送的消息
        worker.on('message', resolve)
        worker.on('error', reject)
        worker.on('exit', (code) => {
            if (code !== 0) reject(new Error(`Worker stopped with exit code ${code}`))
        })
    })
}

app.use(router.routes())
app.listen(9000, () => {
    console.log('Server is running on 9000')
})
Nach dem Login kopieren

新增 fibo.js 文件,用来处理复杂计算任务:

const { workerData, parentPort } = require('worker_threads')
const { num } = workerData

const start = Date.now()
// 斐波那契数列
const fibo = (n) => {
    return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1
}
fibo(num)

parentPort.postMessage({
    pid: process.pid,
    duration: Date.now() - start
})
Nach dem Login kopieren

执行上文的 axios.js,此时将 app.js 中的 fibo 计算次数改为 43,用来模拟更复杂的计算任务:

Eine eingehende Analyse der Prozesse und Threads in Node

可以看到,将 CPU 密集型的计算任务交给子线程处理时,主线程不再被阻塞,只需等待子线程处理完成后,主线程接收子线程返回的结果即可,其他请求不再受影响。
上述代码是演示创建 worker 线程的过程和效果,实际开发中,请使用线程池来代替上述操作,因为频繁创建线程也会有资源的开销。

线程是 CPU 调度的一个基本单位,只能同时执行一个线程的任务,同一个线程也只能被一个 CPU 调用。

我们再回味下,本小节开头提到的线程和 CPU 的描述,此时由于是新的线程,可以在其他 CPU 核心上执行,可以更充分的利用多核 CPU。

2.4、多进程

Node.js 为了能充分利用 CPU 的多核能力,提供了 cluster 模块,cluster 可以通过一个父进程管理多个子进程的方式来实现集群的功能。

  • child_process 子进程,衍生新的 Node.js 进程并使用建立的 IPC 通信通道调用指定的模块。
  • cluster 集群,可以创建共享服务器端口的子进程,工作进程使用 child_process 的 fork 方法衍生。

cluster 底层就是 child_process,master 进程做总控,启动 1 个 agent 进程和 n 个 worker 进程,agent 进程处理一些公共事务,比如日志等;worker 进程使用建立的 IPC(Inter-Process Communication)通信通道和 master 进程通信,和 master 进程共享服务端口。

Eine eingehende Analyse der Prozesse und Threads in Node

新增 fibo-10.js,模拟发送 10 次请求:

// fibo-10.js
const axios = require('axios')

const url = `http://127.0.0.1:9000/fibo?num=38`
const start = Date.now()

for (let i = 0; i  {
        console.log(res.data, `耗时: ${ Date.now() - start }ms`)
    })
}
Nach dem Login kopieren

可以看到,只使用了一个进程,10 个请求慢慢阻塞,累计耗时 15 秒:

Eine eingehende Analyse der Prozesse und Threads in Node

接下来,将 app.js 稍微改动下,引入 cluster 模块:

// app.js
const cluster = require('cluster')
const http = require('http')
const numCPUs = require('os').cpus().length
// const numCPUs = 10 // worker 进程的数量一般和 CPU 核心数相同
const Koa = require('koa')
const router = require('koa-router')()
const app = new Koa()

// 用来测试是否被阻塞
router.get('/test', (ctx) => {
    ctx.body = {
        pid: process.pid,
        msg: 'Hello World'
    }
})
router.get('/fibo', (ctx) => {
    const { num = 38 } = ctx.query
    const start = Date.now()
    // 斐波那契数列
    const fibo = (n) => {
        return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1
    }
    fibo(num)

    ctx.body = {
        pid: process.pid,
        duration: Date.now() - start
    }
})
app.use(router.routes())

if (cluster.isMaster) {
    console.log(`Master ${process.pid} is running`)
    
    // 衍生 worker 进程
    for (let i = 0; i  {
        console.log(`worker ${worker.process.pid} died`)
    })
} else {
    app.listen(9000)
    console.log(`Worker ${process.pid} started`)
}
Nach dem Login kopieren

执行 node app.js 启动服务,可以看到,cluster 帮我们创建了 1 个 master 进程和 4 个 worker 进程:

Eine eingehende Analyse der Prozesse und Threads in Node

Eine eingehende Analyse der Prozesse und Threads in Node

通过 fibo-10.js  模拟发送 10 次请求,可以看到,四个进程处理 10 个请求耗时近 9 秒:

Eine eingehende Analyse der Prozesse und Threads in Node

Wenn 10 Worker-Prozesse gestartet werden, sehen Sie sich den Effekt an:

Eine eingehende Analyse der Prozesse und Threads in Node

Es dauert nur weniger als 3 Sekunden, aber die Anzahl der Prozesse ist nicht unbegrenzt. In der täglichen Entwicklung entspricht die Anzahl der Worker-Prozesse im Allgemeinen der Anzahl der CPU-Kerne.

2.5. Multiprozessbeschreibung

Die Aktivierung von Multiprozessen dient nicht ausschließlich der Bewältigung hoher Parallelität, sondern der Lösung des Problems der unzureichenden Multi-Core-CPU-Auslastung von Node.js.
Der vom übergeordneten Prozess über die Fork-Methode abgeleitete untergeordnete Prozess verfügt über dieselben Ressourcen wie der übergeordnete Prozess, ist jedoch unabhängig und teilt keine Ressourcen miteinander. Die Anzahl der Prozesse wird normalerweise anhand der Anzahl der CPU-Kerne festgelegt, da die Systemressourcen begrenzt sind.

3. Zusammenfassung

1. Die meisten Lösungen für CPU-intensive Rechenaufgaben können durch Multiprozesslösungen ersetzt werden
2 Blockieren Sie die CPU. Es ist am besten, keine intensiven Aufgaben im Hauptthread zu verarbeiten.
3 Streben Sie nicht blind nach hoher Leistung und hoher Parallelität Agilität ist das, was das Projekt benötigt, und das sind auch die Lightweight-Funktionen von Node.j.
4. Es gibt viele Konzepte von Prozessen und Threads in Node.js, die im Artikel erwähnt, aber nicht im Detail besprochen oder nicht erwähnt werden, wie zum Beispiel: libuv, IPC-Kommunikationskanal, Multiprozess von Node.js zugrunde liegendes I/ O Wie man mit geplanten Aufgaben, Agentprozessen usw. umgeht, wenn Ressourcen zwischen Daemons und Prozessen nicht gemeinsam genutzt werden
5. Der obige Code kann unter https://github.com/liuxy0551/node-process-thread eingesehen werden.

Weitere Informationen zu Knoten finden Sie unter: nodejs-Tutorial!

Das obige ist der detaillierte Inhalt vonEine eingehende Analyse der Prozesse und Threads in Node. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:cnblogs.com
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage
Über uns Haftungsausschluss Sitemap
Chinesische PHP-Website:Online-PHP-Schulung für das Gemeinwohl,Helfen Sie PHP-Lernenden, sich schnell weiterzuentwickeln!