溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Node.js中怎么實(shí)現(xiàn)線程睡眠

發(fā)布時(shí)間:2021-07-20 16:36:09 來源:億速云 閱讀:445 作者:Leah 欄目:web開發(fā)

Node.js中怎么實(shí)現(xiàn)線程睡眠,針對這個(gè)問題,這篇文章詳細(xì)介紹了相對應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問題的小伙伴找到更簡單易行的方法。

一:糟糕的 “循環(huán)空轉(zhuǎn)”

下面這段代碼是糟糕的,Node.js 是以單進(jìn)程、單線程的方式啟動(dòng),所有的業(yè)務(wù)代碼都工作在主線程,這樣會(huì)造成 CPU  持續(xù)占用,主線程阻塞對 CPU 資源也是一種浪費(fèi),與真正的線程睡眠相差甚遠(yuǎn)。

const start = new Date(); while (new Date() - start < 2000) {}

Node.js中怎么實(shí)現(xiàn)線程睡眠

運(yùn)行之后如上圖所示,CPU 暴漲,同時(shí)也會(huì)破壞事件循環(huán)調(diào)度,導(dǎo)致其它任務(wù)無法執(zhí)行。

二:定時(shí)器 + Promise 實(shí)現(xiàn) sleep

通過定時(shí)器延遲執(zhí)行函數(shù) setTimeout + Promise 的鏈?zhǔn)揭蕾噷?shí)現(xiàn),本質(zhì)是創(chuàng)建一個(gè)新的  Promise 對象,待定時(shí)器延遲時(shí)間到了執(zhí)行 resolve 函數(shù)這時(shí) then 才會(huì)執(zhí)行,這里 Node.js 執(zhí)行線程是沒有進(jìn)行睡眠的,事件循環(huán)和 V8  等都是正常運(yùn)行的。但這也是目前通用的一種解決方案,因?yàn)槟悴荒茏屩骶€程阻塞,否則程序就無法繼續(xù)工作了。

const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));

在 Node.js 中還可以利用 util 模塊提供的 promisify 方法實(shí)現(xiàn),一種快捷方式。

const { promisify } = require('util'); const sleep = promisify(setTimeout);

因?yàn)槭腔诙〞r(shí)器與 Promise 所以也自然是異步的方式了,使用時(shí)也要注意,如下所示:

// async await 的方式 async function test() {   console.log(1);   await sleep(3000);   console.log(2); }  // Promise 的鏈?zhǔn)秸{(diào)用方式 async function test() {   console.log(1);   sleep(3000).then(() => {     console.log(2);   }); }

三:零 CPU 開銷真正的事件循環(huán)阻止 sleep 實(shí)現(xiàn)

ECMA262 草案提供了 Atomics.wait API  來實(shí)現(xiàn)線程睡眠,它會(huì)真正的阻塞事件循環(huán),阻塞線程直到超時(shí)。

該方法 Atomics.wait(Int32Array, index, value[, timeout]) 會(huì)驗(yàn)證給定的 Int32Array  數(shù)組位置中是否仍包含其值,在休眠狀態(tài)下會(huì)等待喚醒或直到超時(shí),返回一個(gè)字符串表示超時(shí)還是被喚醒。

同樣的因?yàn)槲覀兊臉I(yè)務(wù)是工作在主線程,避免在主線程中使用,在 Node.js 的工作線程中可以根據(jù)實(shí)際需要使用。

/**  * 真正的阻塞事件循環(huán),阻塞線程直到超時(shí),不要在主線程上使用   * @param {Number} ms delay  * @returns {String} ok|not-equal|timed-out  */ function sleep(ms) {   const valid = ms > 0 && ms < Infinity;   if (valid === false) {     if (typeof ms !== 'number' && typeof ms !== 'bigint') {       throw TypeError('ms must be a number');     }     throw RangeError('ms must be a number that is greater than 0 but less than Infinity');   }    return Atomics.wait(int32, 0, 0, Number(ms)) }  sleep(3000)

由于本節(jié)我們僅是在講解 sleep 的實(shí)現(xiàn),所以關(guān)于 Atomics.wait 方法睡眠之后如何被其它線程喚醒也不再此處講了,之后我會(huì)寫一講  Node.js 中的工作線程相關(guān)文章,到時(shí)會(huì)再次介紹。

四:基于 N-API 擴(kuò)展使用 C 語言實(shí)現(xiàn) sleep

通過 Addon 的方式使用 N-API 編寫 C/C++ 插件,借助其提供的系統(tǒng) sleep()  函數(shù)實(shí)現(xiàn)。

// sleep.c #include <assert.h> #include <unistd.h> #include <node_api.h>  napi_value sleepFn(napi_env env, napi_callback_info info) {   napi_status status;   size_t argc = 1;   napi_value argv[1];    status = napi_get_cb_info(env, info, &argc, argv, NULL, NULL);   assert(status == napi_ok);   if (argc < 1) {     napi_throw_type_error(env, NULL, "ms is required");     return NULL;   }    napi_valuetype valueType;   napi_typeof(env, argv[0], &valueType);   if (valueType != napi_number) {     napi_throw_type_error(env, NULL, "ms must be a number");     return NULL;   }    int64_t s;   napi_get_value_int64(env, argv[0], &s);   sleep(s);   return NULL; }  napi_value init(napi_env env, napi_value exports) {   napi_status status;   napi_property_descriptor descriptor = {     "sleep",     0,     sleepFn,     0,     0,     0,     napi_default,     0   };   status = napi_define_properties(env, exports, 1, &descriptor);   assert(status == napi_ok);   return exports; }  NAPI_MODULE(sleep, init);

經(jīng)過一系列編譯之后,引入 .node 文件直接使用。

// app.js const { sleep } = require('./build/Release/sleep.node'); sleep(3);

五:easy-sleep 模塊

這是筆者寫的一個(gè)小模塊  https://github.com/qufei1993/easy-sleep,其實(shí)也是對以上幾種方法的整合,包含了 C 插件的編寫,使用如下:

// Install npm install easy-sleep -S  // Async sleep const { sleep } = require('easy-sleep'); await sleep(3000);  // Thread sleep const { Thread } = require('easy-sleep'); Thread.sleep();

關(guān)于Node.js中怎么實(shí)現(xiàn)線程睡眠問題的解答就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注億速云行業(yè)資訊頻道了解更多相關(guān)知識。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI