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 |