文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Node.js中怎么实现线程睡眠

2024-04-02 19:55

关注

Node.js中怎么实现线程睡眠,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。

一:糟糕的 “循环空转”

下面这段代码是糟糕的,Node.js 是以单进程、单线程的方式启动,所有的业务代码都工作在主线程,这样会造成 CPU  持续占用,主线程阻塞对 CPU 资源也是一种浪费,与真正的线程睡眠相差甚远。

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

Node.js中怎么实现线程睡眠

运行之后如上图所示,CPU 暴涨,同时也会破坏事件循环调度,导致其它任务无法执行。

二:定时器 + Promise 实现 sleep

通过定时器延迟执行函数 setTimeout + Promise 的链式依赖实现,本质是创建一个新的  Promise 对象,待定时器延迟时间到了执行 resolve 函数这时 then 才会执行,这里 Node.js 执行线程是没有进行睡眠的,事件循环和 V8  等都是正常运行的。但这也是目前通用的一种解决方案,因为你不能让主线程阻塞,否则程序就无法继续工作了。

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

在 Node.js 中还可以利用 util 模块提供的 promisify 方法实现,一种快捷方式。

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

因为是基于定时器与 Promise 所以也自然是异步的方式了,使用时也要注意,如下所示:

// async await 的方式 async function test() {   console.log(1);   await sleep(3000);   console.log(2); }  // Promise 的链式调用方式 async function test() {   console.log(1);   sleep(3000).then(() => {     console.log(2);   }); }

三:零 CPU 开销真正的事件循环阻止 sleep 实现

ECMA262 草案提供了 Atomics.wait API  来实现线程睡眠,它会真正的阻塞事件循环,阻塞线程直到超时。

该方法 Atomics.wait(Int32Array, index, value[, timeout]) 会验证给定的 Int32Array  数组位置中是否仍包含其值,在休眠状态下会等待唤醒或直到超时,返回一个字符串表示超时还是被唤醒。

同样的因为我们的业务是工作在主线程,避免在主线程中使用,在 Node.js 的工作线程中可以根据实际需要使用。

 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)

由于本节我们仅是在讲解 sleep 的实现,所以关于 Atomics.wait 方法睡眠之后如何被其它线程唤醒也不再此处讲了,之后我会写一讲  Node.js 中的工作线程相关文章,到时会再次介绍。

四:基于 N-API 扩展使用 C 语言实现 sleep

通过 Addon 的方式使用 N-API 编写 C/C++ 插件,借助其提供的系统 sleep()  函数实现。

// 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);

经过一系列编译之后,引入 .node 文件直接使用。

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

五:easy-sleep 模块

这是笔者写的一个小模块  https://github.com/qufei1993/easy-sleep,其实也是对以上几种方法的整合,包含了 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();

关于Node.js中怎么实现线程睡眠问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注编程网行业资讯频道了解更多相关知识。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-前端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯