nodejs创建线程问题
我们知道在nodejs中可以使用new Worker创建线程。今天有个同学恰好问到,怎么判断创建线程成功,这也是最近开发线程池的时候遇到的问题。nodejs文档里也没有提到如何捕获创建失败这种情况。所以只能通过源码去找答案。不过坏消息是,我们无法捕获这个这个错误。下面看一下源码。我们直接从c++层开始分析。 当我们调用new Worker的时候,最后会调用c++的StartThread函数(node_worker.cc)创建一个线程。
CHECK_EQ(uv_thread_create_ex(&w->tid_, &thread_options, [](void* arg) {
// ...
}, static_cast<void*>(w)), 0);
我们看uv_thread_create_ex的逻辑
int uv_thread_create_ex(uv_thread_t* tid,
const uv_thread_options_t* params,
void (*entry)(void *arg),
void *arg) {
// 忽略部分代码
err = pthread_create(tid, attr, f.out, arg);
return UV__ERR(err);
}
接着我们看一下pthread_create的返回值定义
On success, pthread_create() returns 0; on error, it returns an error number, and the contents of *thread are undefined.
所以,如果uv_thread_create_ex返回非0,即pthread_create返回非0。表示报错。我们回头看一下返回非0时,c++的处理。我们对c++层的CHECK_EQ(uv_thread_create_ex(…), 0)进行宏展开。
#define CHECK_EQ(a, b) CHECK((a) == (b))
#define CHECK(expr)
do {
if (UNLIKELY(!(expr))) {
ERROR_AND_ABORT(expr);
}
} while (0)
#define UNLIKELY(expr) expr
通过一些列展开,最后变成
do {
if (!(返回值 == 0)) {
ERROR_AND_ABORT(expr);
}
} while (0)
因为创建线程时返回非0,所以这里是true。我们继续看ERROR_AND_ABORT
#define ERROR_AND_ABORT(expr)
do {
static const node::AssertionInfo args = {
__FILE__ ":" STRINGIFY(__LINE__), #expr, PRETTY_FUNCTION_NAME
};
node::Assert(args);
} while (0)
拼接错误信息,然后执行node::Assert(args);
[[noreturn]] void Assert(const AssertionInfo& info) {
char name[1024];
GetHumanReadableProcessName(&name);
fprintf(stderr,
"%s: %s:%s%s Assertion `%s' failed.n",
name,
info.file_line,
info.function,
*info.function ? ":" : "",
info.message);
fflush(stderr);
Abort();
}
重点是Abort,
[[noreturn]] void Abort() {
DumpBacktrace(stderr);
fflush(stderr);
ABORT_NO_BACKTRACE();
}
继续看ABORT_NO_BACKTRACE
#ifdef _WIN32
#define ABORT_NO_BACKTRACE() _exit(134)
#else
#define ABORT_NO_BACKTRACE() abort()
#endif
所以最终调用的是_exit或abort退出或者终止进程。我们讨论linux下的情况。我们看abort函数的说明
The abort() function first unblocks the SIGABRT signal, and then raises that signal for the calling process (as though raise(3) was called). This results in the abnormal termination of the process unless the SIGABRT signal is caught and the signal handler does not return (see longjmp(3)). If the SIGABRT signal is ignored, or caught by a handler that returns, the abort() function will still terminate the process. It does this by restoring the default disposition for SIGABRT and then raising the signal for a second time.
abort函数会给进程发送SIGABRT信号,我们可以注册函数处理这个信号,不过我们还是无法阻止进程的退出,因为他执行完我们的处理函数后,会把处理函数注册为系统的默认的,然后再次发送SIGABRT信号,而默认的行为就是终止进程。我们来个测试。
const { Worker, threadId } = require('worker_threads');
for (let i = 0; i < 1000; i++) {
const worker = new Worker('var a = 1;', { eval: true });
}
我们创建1000个线程。结果
总结:在nodejs创建过多的线程可能会导致进程终止。而我们无法阻止这个行为。所以在nodejs里使用多线程的时候,我们需要注意的就是不要开启过多的线程,而在创建线程的时候,我们也不需要关注是否成功,因为只要进程不挂掉,那就是成功。对于业务错误我们可以注册error事件处理,在new Worker的时候,我们可以加try catch。可以捕获一下参数错误的情况。
- 通过shell脚本生成数据统计信息的报表 (笔记65天)
- 物化视图全量刷新的简单测试(63天)
- Golang语言社区--Go操作CSV文件
- TiDB 源码阅读系列文章(四)Insert 语句概览
- 食品安全溯源区块链解决方案探索
- Docker 简介与安装
- 经典Java面试题收集
- 关于update语句的性能测试(62天)
- 物化视图刷新的问题及分析(61天)
- 使用python+机器学习方法进行情感分析(详细步骤)
- 关于primary key和foreign key的问题处理(60天)
- Git 进阶指南
- Python 文本挖掘:使用情感词典进行情感分析(算法及程序设计)
- 可能是地球上最好用的 Mac 词典工具
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 机器学习基础:令你事半功倍的pipeline处理机制
- django 中如何将字典变量传给template视图层的JS
- Spring第三天:Spring的AOP的注解开发、Spring的声明式事务、JdbcTemplate
- Spring Boot中集成Slf4j 与Logback
- 一文搞定 Linux 常用高频命令
- 推荐一款科研必备的Python数据可视化神器——PyQtGraph
- 机器学习基础:可视化方式理解决策树剪枝
- 神级代码注释-这次是来搞笑的
- Gremlin 图查询概述
- JS,PHP,Python,Java对JSON数据的处理
- 基于Canal与Flink实现数据实时增量同步(二)
- Spring第四天:SSH的整合、HibernateTemplate的使用、OpenSessionInViewFilter的使用
- IDEA 下单程序多端口不同配置独立运行
- 基于Canal与Flink实现数据实时增量同步(一)
- 8848钛金手机之nacos的注册发现