日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

go/node/python 多进程与多核cpu

發(fā)布時間:2025/6/16 80 豆豆
生活随笔 收集整理的這篇文章主要介紹了 go/node/python 多进程与多核cpu 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

node

node單線程,沒有并發(fā),但是可以利用cluster進行多cpu的利用。cluster是基于child_process的封裝,幫你做了創(chuàng)建子進程,負載均衡,IPC的封裝。

const cluster = require('cluster'); const http = require('http');if (cluster.isMaster) {let numReqs = 0;setInterval(() => {console.log(`numReqs = ${numReqs}`);}, 1000);function messageHandler(msg) {if (msg.cmd && msg.cmd === 'notifyRequest') {numReqs += 1;}}const numCPUs = require('os').cpus().length;for (let i = 0; i < numCPUs; i++) {cluster.fork();}for (const id in cluster.workers) {cluster.workers[id].on('message', messageHandler);}} else {// Worker processes have a http server.http.Server((req, res) => {res.writeHead(200);res.end('hello world\n');process.send({ cmd: 'notifyRequest' });}).listen(8000); }

我們通過cluster.fork()來創(chuàng)造幾個子進程,讓子進程來替我們工作。在fork的時候會傳一個參數(shù)到子進程,cluster.isMaster就是根據(jù)有沒有這個參數(shù)判斷的。
如果是子進程就起一個server。
每個子進程都會綁定到8000端口,這不會引起端口占用嗎?
答案是不會,因為listen并不會真的監(jiān)聽到8000端口,它會通過IPC把子進程的消息傳到主進程,主進程會創(chuàng)建服務(wù)器,然后調(diào)用子進程的回調(diào)。
在子進程的回調(diào)中:子進程會根據(jù)主進程是否返回handle句柄來執(zhí)行下一步的操作,如果沒有handle句柄,說明在負載均衡的策略沒有選中本進程。那么就自己造一個handle對象返回。
那自己造個對象怎么返回請求呢?
請求到主進程,主進程會分發(fā)請求,處理到該請求的子進程會通過IPC與主進程通信,這樣就完成了一個請求的響應(yīng)。

通過cluster完成單機器的負載均衡,那么多機器呢?還是得用nginx。

node & pm2

pm2 是node的進程管理工具,它封裝了cluster,可以通過命令行來創(chuàng)建多個進程來處理。

寫個config文件:
app.json

{"name" : "app","script" : "src/main.js","watch" : true,"merge_logs" : true,"instances" : "max", // 使用cluster"error_file" : "./log/error.log","out_file" : "./log/asccess.log","pid_file" : "./log/pid.pid","cwd" : "./","max_restarts" : 10, "min_uptime": "10s","env": {"NODE_ENV": "development","BABEL_ENV": "node"},"env_prod" : {"NODE_ENV": "production"} } pm2 start app.json

也可以不寫配置文件直接寫pm2 start -i 4 --name server index.js
開啟4個instance。

通過參數(shù)開啟多個子進程,而不需要修改我們的業(yè)務(wù)代碼。

go

go也是非阻塞io,Golang默認所有的任務(wù)都在一個cpu核里,如果想使用多核來跑goroutine的任務(wù),需要配置runtime.GOMAXPROCS。
自從Go 1.5開始, Go的GOMAXPROCS默認值已經(jīng)設(shè)置為 CPU的核數(shù),我們不用手動設(shè)置這個參數(shù)。
我們先說說go的并發(fā)。
go本身就可以通過go關(guān)鍵字來進行并發(fā)操作。go關(guān)鍵字創(chuàng)建的并發(fā)單元在go中叫g(shù)oroutine。
比如:

package mainimport ("fmt""time",// "runtime" ) func main() {go func(){fmt.Println("123")}()go func(){fmt.Println("456")}()// runtime.Gosched()fmt.Println("789")time.Sleep(time.Second) }

會打印789 ,123,456,或者 780,456,123。
在主線程開始就通過go字段開啟了2個goroutine,兩個goroutine的執(zhí)行順序不確定。
如果當(dāng)前goroutine發(fā)生阻塞,它就會讓出CPU給其他goroutine。
如果當(dāng)前goroutine不發(fā)生阻塞,一直在執(zhí)行,那么什么時候執(zhí)行其他goroutine就看go調(diào)度器的處理了。

不過go提供runtime.Gosched()來達到讓出CPU資源效果的函數(shù),當(dāng)然不是不執(zhí)行,會在之后的某個時間段執(zhí)行。如果把注釋去掉,789就會最后執(zhí)行。

單核的時候其實goroutine并不是真的“并行”,goroutine都在一個線程里,它們之間通過不停的讓出時間片輪流運行,達到類似并行的效果。
如果我在123,或者456之前加 time.Sleep(time.Second)。那么CPU的資源又會轉(zhuǎn)讓回主進程。

當(dāng)一個goroutine發(fā)生阻塞,Go會自動地把與該goroutine處于同一系統(tǒng)線程的其他goroutines轉(zhuǎn)移到另一個系統(tǒng)線程上去,以使這些goroutines不阻塞,主線程返回的時候goroutines又進入runqueue

下面這段代碼:

import ("fmt""runtime" )var quit chan int = make(chan int)func loop() {for i := 0; i < 100; i++ { //為了觀察,跑多些fmt.Printf("%d ", i)}quit <- 0 }func main() {runtime.GOMAXPROCS(1)go loop()go loop()for i := 0; i < 2; i++ {<-quit} }

會打印什么呢?
runtime.GOMAXPROCS(2)改成雙核cpu,又會打印什么呢?
我們能看到,雙核cpu的時候,goroutine會真正的并發(fā)執(zhí)行而不是并行。他們會搶占式的執(zhí)行。

參考https://studygolang.com/articles/1661

python

python是有多線程的,但是python有g(shù)il影響了他的多cpu利用。
GIL是CPython中特有的全局解釋器鎖
這把鎖在解釋器進程中是全局有效的,它主要鎖定Python線程的CPU執(zhí)行資源。
想要執(zhí)行多核的進程需要滿足2個條件

  • 被操作系統(tǒng)調(diào)度出來【操作系統(tǒng)允許它占用CPU】
  • 獲取到GIL【CPython解釋器允許它執(zhí)行指令】
  • python在單核cpu上執(zhí)行沒有問題,這個線程總能獲得gil,但是在多核的時候,線程會出現(xiàn)競爭,GIL只能同時被一個線程申請到,沒申請到的就會被阻塞,就會一直處于閑置狀態(tài)。
    到線程切換時間然后睡眠,被喚醒之后獲取gil又失敗,惡性循環(huán)。

    特別是計算型線程,會一直持有g(shù)il。

    GIL 可以被 C 擴展釋放,Python 標(biāo)準(zhǔn)庫會在每次 I/O 阻塞結(jié)束后釋放 GIL,因此 GIL 不會對 I/O 服務(wù)器產(chǎn)生很大的性能影響。因此你可以 fork 進程或者創(chuàng)建多線程來創(chuàng)建網(wǎng)絡(luò)服務(wù)器處理異步 I/O,GIL 在這種情況下并沒有影響。

    解決方案:

  • 使用python3.4或更高版本(對GIL機制進行了優(yōu)化)
  • 使用多進程替換多線程(多進程之間沒有GIL,但是進程本身的資源消耗較多)
  • 指定cpu運行線程(使用affinity模塊)
  • 全IO密集型任務(wù)時使用多線程
  • 協(xié)程 (gevent模塊)
  • Python 3.2開始使用新的GIL。新的GIL實現(xiàn)中用一個固定的超時時間來指示當(dāng)前的線程放棄全局鎖。在當(dāng)前線程保持這個鎖,且其他線程請求這個鎖時,當(dāng)前線程就會在5毫秒后被強制釋放該鎖。

    總結(jié)

    node是沒有多線程的利用的,只能用多進程來利用多核cpu,python因為gil的問題,也沒法完全利用多線程,但是有一些神奇的方案可以利用比如指定cpu運行。
    go的實現(xiàn)是比較好的,畢竟是后來的語言,可以多核跑協(xié)程,來利用cpu

    轉(zhuǎn)載于:https://www.cnblogs.com/dh-dh/p/9174294.html

    總結(jié)

    以上是生活随笔為你收集整理的go/node/python 多进程与多核cpu的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。