前言
从用法和官方介绍角度来看,napi_threadsafe_function 和 napi_async_work 似乎是两个完全不相同的两个东西,但从源码分析他们实现的原理,是有很大重合度。以至于使用场景亦有重合的地方。
读前须知
- uv_async_send、uv_async_init、uv_queue_work 具体用法和作用。
- napi_async_work 系列 API 具体用法和作用。
- 线程安全函数 API 具体用法和作用。
- Libuv 线程池里的线程都有 napi env 环境和都持有一个 event-loop。
- JS 主线程是 Libuv 线程池中某一个线程,napi_queue_async_work 创建的线程也在 Libuv 线程池里。
napi_async_work
napi_async_work 解决了什么问题?
对于耗时的操作。如果在 Libuv 的主线程里执行的话, 就会阻塞后面的任务执行。所以 Libuv 里维护了一个线程池。简单的说,napi_async_work 负责创建一个新线程放入 Libuv 线程池,去执行耗时操作,待线程执行结束,将回调函数 push 到主线程的 eventloop 内等待被执行。
源码分析 (请下载 node.js 源码,并且结合源码阅读)
使用 napi_create_async_work 创建异步 work;源码中实例化了 uvimpl::Work,把实例引用地址赋值给 result。
napi_create_async_work(napi_env env,
napi_value async_resource,
napi_value async_resource_name,
napi_async_execute_callback execute,
napi_async_complete_callback complete,
void* data,
napi_async_work* result) {
uvimpl::Work* work = uvimpl::Work::New(reinterpret_cast<node_napi_env>(env),
resource,
resource_name,
execute,
complete,
data);
*result = reinterpret_cast<napi_async_work>(work);
return napi_clear_last_error(env);
}
uvimpl::Work 实际上继承了 ThreadPoolWork,所以说上面的实例是 ThreadPoolWork 实例
class Work : public node::AsyncResource, public node::ThreadPoolWork {
private:
explicit Work(node_napi_env env,
v8::Local<v8::Object> async_resource,
v8::Local<v8::String> async_resource_name,
napi_async_execute_callback execute,
napi_async_complete_callback complete = nullptr,
void* data = nullptr)
: AsyncResource(