標籤:

nodejs中,zlib.gzip系列純cpu計算函數為什麼會有非同步版本?


純 CPU 計算就不能流式了?

要知道 Node.js 在用戶層是單線程的,你用同步版本的話,直接會阻塞時間循環——這期間你做不了任何事情。

而如果用了非同步版本,它會採用流式去操作,並且這些操作都是在 libuv 的其它線程中完成,並不會阻塞事件循環,並且在 Stream 流數據的空檔依舊可以有很多主事件循環中的操作可以做。

同步版本是顯示將所有的計算都抬到明面上來阻塞了,相當於你在其它語言中寫個單線程程序,而非同步版本實際上是跑在多線程下,主事件循環上的安排還是繼續在跑,並不會完全被阻塞住。


JS 的執行環境是單線程的,但是實現 Node 環境的語言 C++ 可以是多線程的,所以如果不希望計算量大的操作阻塞 JS 執行,那就用 C++ 實現(這樣的執行速度也會更快),再用 JS 去調用。


難道不是為什麼會有同步版本嗎


這實際上是理想的情況啊。都說 Node.js 單線程,不適合 CPU 密集型的場景。但是如果能把所有 CPU 密集型的操作,都封裝成非同步的「IO 型」操作,那這個問題就解決了。

現在的問題不是 zlib 等計算函數是非同步的,而是你自己寫的計算函數默認不是非同步的,即使封裝成非同步的它也不會多開一個線程/進程去跑。

除非你也寫 C++ 模塊,但這樣用 JS(對我來說是 TS)帶來的方便性就沒了;或者也可以做成 worker 形式,單獨開進程去跑,用某種 RPC 去調用,化激計算為 IO。雖然總體而言 Node.js 的計算性能可能就不高,但我覺得這麼做還是有意義的。


阻塞不僅僅指 IO 操作,可能出現執行慢,耗資源的地方,感覺有非同步版本都正常。


Why zlib.deflate(buf, callback) is async?

這個回答大概能解釋你的一部分疑惑?


因為nodejs有病。

nodejs認為event loop和非同步io能描述世界萬物,跟java認為OO能描述世界萬物一樣,都是一個尿性,都是發神經,絮絮叨叨,臭不可聞。

但很多時候你得忍著,因為不管它多麼爛,都已經這樣了,這就是歷史。

跳腳大罵後,看看有沒有同步的介面,沒有的話趕緊用promise封一層,await一下。

還是不解氣,沒事,把那死人庫丟了,自己寫一個全部都是同步介面的庫,練手的機會來了,開心不?


主要是為了不影響 v8 的線程執行咯…


也許為了以後支持多核實現。方便兼容以前的api。畢竟多核後可以是非同步的。又或者底層可能就是多線程的。在壓縮的同時能保證你的電腦不當機。


這就和fs庫一樣,其實都是多線程在跑。eventloop只是等待多線程執行完,而不是把讀寫文件這個操作放在eventloop中執行。

當然大部分js寫的計算(比如1+1)還是在eventloop執行完,才執行下一個事件。


因為它們很耗CPU,所以必須要有非同步的版本;以web業務來說,就是會影響QPS。

實現上,就是開單獨的線程來做這種重CPU的運算,使得主線程可以繼續執行別的業務邏輯。

壓縮是同步的情況:

在紅框的時間內,儘管別的請求到來,但不能得到及時的處理

壓縮是非同步的情況:

主線程不被阻塞,可以繼續處理其它的請求


你大概不希望一個 gzip 操作卡住你 server,所以有非同步版本。這和 Node.js 的非同步信仰沒有半毛錢關係。再說了,現在有了 async 和 await,寫起來沒什麼差別。


你提的這兩個函數是絕對推薦使用非同步的,這樣js的主進程就會被釋放出來處理其他事情/請求。如果你採用同步的方式,特別是伺服器端應用,每次處理大文件,你就感覺死住了一樣,所有請求都卡頓了。


推薦閱讀:

es6 import from xx , 是怎麼實現找到 node_modules目錄下的?
Node.js伺服器端項目怎麼打包成單文件?
如何在Node.js或TypeScript中實現for..of形式的按行讀文件?

TAG:Nodejs |