该 pbkdf2 function具有JavaScript实现,但它实际上将要完成的所有工作委托给C ++端。
pbkdf2
env->SetMethod(target, "pbkdf2", PBKDF2); env->SetMethod(target, "generateKeyPairRSA", GenerateKeyPairRSA); env->SetMethod(target, "generateKeyPairDSA", GenerateKeyPairDSA); env->SetMethod(target, "generateKeyPairEC", GenerateKeyPairEC); NODE_DEFINE_CONSTANT(target, OPENSSL_EC_NAMED_CURVE); NODE_DEFINE_CONSTANT(target, OPENSSL_EC_EXPLICIT_CURVE); NODE_DEFINE_CONSTANT(target, kKeyEncodingPKCS1); NODE_DEFINE_CONSTANT(target, kKeyEncodingPKCS8); NODE_DEFINE_CONSTANT(target, kKeyEncodingSPKI); NODE_DEFINE_CONSTANT(target, kKeyEncodingSEC1); NODE_DEFINE_CONSTANT(target, kKeyFormatDER); NODE_DEFINE_CONSTANT(target, kKeyFormatPEM); NODE_DEFINE_CONSTANT(target, kKeyTypeSecret); NODE_DEFINE_CONSTANT(target, kKeyTypePublic); NODE_DEFINE_CONSTANT(target, kKeyTypePrivate); env->SetMethod(target, "randomBytes", RandomBytes); env->SetMethodNoSideEffect(target, "timingSafeEqual", TimingSafeEqual); env->SetMethodNoSideEffect(target, "getSSLCiphers", GetSSLCiphers); env->SetMethodNoSideEffect(target, "getCiphers", GetCiphers); env->SetMethodNoSideEffect(target, "getHashes", GetHashes); env->SetMethodNoSideEffect(target, "getCurves", GetCurves); env->SetMethod(target, "publicEncrypt", PublicKeyCipher::Cipher<PublicKeyCipher::kPublic, EVP_PKEY_encrypt_init, EVP_PKEY_encrypt>); env->SetMethod(target, "privateDecrypt", PublicKeyCipher::Cipher<PublicKeyCipher::kPrivate, EVP_PKEY_decrypt_init, EVP_PKEY_decrypt>); env->SetMethod(target, "privateEncrypt", PublicKeyCipher::Cipher<PublicKeyCipher::kPrivate, EVP_PKEY_sign_init, EVP_PKEY_sign>); env->SetMethod(target, "publicDecrypt", PublicKeyCipher::Cipher<PublicKeyCipher::kPublic, EVP_PKEY_verify_recover_init, EVP_PKEY_verify_recover>);
资源: https://github.com/nodejs/node/blob/master/src/node_crypto.cc
Libuv模块还有另一项责任,它与标准库中的某些特定功能相关。
对于某些标准库函数调用,Node C ++端和Libuv决定完全在事件循环之外进行昂贵的计算。
相反,他们使用称为线程池的东西,线程池是一系列四个线程,可用于运行计算成本高昂的任务,如 pbkdf2 功能。
默认情况下,Libuv在此线程池中创建4个线程。
除了事件循环中使用的线程之外,还有四个其他线程可用于卸载需要在我们的应用程序内部进行的昂贵计算。
Node标准库中包含的许多函数都会自动使用此线程池。该 pbkdf2 功能就是其中之一。
此线程池的存在非常重要。
所以Node并不是真正的单线程,因为Node还有其他线程用于执行一些计算成本高昂的任务。
如果事件池负责执行计算成本高昂的任务,那么我们的Node应用程序就无法执行任何其他操作。
我们的CPU一个接一个地运行一个线程内的所有指令。
通过使用线程池,我们可以在计算发生时在事件循环中执行其他操作。
看起来所讨论的一些实体(例如:libev等)已经失去了相关性,因为它已经有一段时间了,但我认为这个问题仍然具有很大的潜力。
让我尝试在抽象的UNIX环境中,在Node的上下文中,借助抽象示例来解释事件驱动模型的工作。
的 计划的观点: 强>
上面的事件机制称为libuv AKA事件循环框架。 Node利用此库来实现其事件驱动的编程模型。
的 Node的观点: 强>
虽然大多数功能都以这种方式迎合,但文件操作的一些(异步版本)是在附加线程的帮助下执行的,并且很好地集成到libuv中。虽然网络I / O操作可以等待期望外部事件,例如另一个端点响应数据等,但文件操作需要来自节点本身的一些工作。例如,如果你打开一个文件并等待fd准备好数据,它就不会发生,因为没有人正在阅读!同时,如果您从主线程中的内联文件中读取,它可能会阻止程序中的其他活动,并且可能会产生可见问题,因为与cpu绑定活动相比,文件操作非常慢。因此,从程序的角度来看,内部工作线程(可通过UV_THREADPOOL_SIZE环境变量配置)用于对文件进行操作,而事件驱动的抽象则完整无缺。
希望这可以帮助。
我一直在亲自阅读node.js&amp;的源代码。 V8。
当我尝试理解node.js架构以编写本机模块时,我遇到了类似的问题。
我在这里发布的是我对node.js的理解,这也可能有点偏离轨道。
Libev 是事件循环,它实际上在node.js内部运行,以执行简单的事件循环操作。它最初是为* nix系统编写的。 Libev为运行的进程提供了一个简单但优化的事件循环。你可以阅读更多关于libev的内容 这里 。
LibEio 是一个异步执行输入输出的库。它处理文件描述符,数据处理程序,套接字等。您可以在此处阅读更多相关信息 这里 。
LibUv 是libeio,libev,c-ares(用于DNS)和iocp(用于windows asynchronous-io)的顶层的抽象层。 LibUv执行,维护和管理事件池中的所有io和事件。 (在libeio线程池的情况下)。你应该看看 Ryan Dahl的教程 在libUv上。这将开始让你更了解libUv如何工作,然后你将了解node.js如何在libuv和v8的顶部工作。
要了解javascript事件循环,您应该考虑观看这些视频
要查看libeio如何与node.js一起使用以创建异步模块,您应该看到 这个例子 。
基本上,node.js内部发生的是v8循环运行并处理所有javascript部分以及C ++模块[当它们在主线程中运行时(根据官方文档node.js本身是单线程的)]。当在主线程之外时,libev和libeio在线程池中处理它,libev提供与主循环的交互。所以根据我的理解,node.js有1个永久事件循环:这是v8事件循环。为了处理C ++异步任务,它使用了一个线程池[via libeio&amp;解放。
例如:
eio_custom(Task,FLAG,AfterTask,Eio_REQUEST);
所有模块中出现的通常都是调用该函数 Task 在线程池中。当它完成后,它会调用 AfterTask 函数在主线程中。而 Eio_REQUEST 是请求处理程序,它可以是一个结构/对象,其动机是提供线程池和主线程之间的通信。
Task
AfterTask
Eio_REQUEST
NodeJs架构中有一个事件循环。
节点应用程序在单线程事件驱动模型中运行。但是,Node在后台实现了一个线程池,以便可以执行工作。
Node.js将工作添加到事件队列,然后运行事件循环的单个线程将其拾取。事件循环抓取事件队列中的顶部项目,执行它,然后抓取下一个项目。
当执行更长寿的代码或具有阻塞I / O的代码时,它不是直接调用函数,而是将函数添加到事件队列以及将在函数完成后执行的回调。当Node.js事件队列中的所有事件都已执行时,Node.js应用程序终止。
当我们的应用程序功能阻塞I / O时,事件循环开始引发问题。
Node.js使用事件回调来避免必须等待阻塞I / O.因此,执行阻塞I / O的任何请求都在后台的不同线程上执行。
当从事件队列中检索阻止I / O的事件时,Node.js从线程池中检索线程,并在那里而不是在主事件循环线程上执行该函数。这可以防止阻塞I / O占用事件队列中的其余事件。
作为一个javascript初学者,我也有同样的疑问,NodeJS是否包含2个事件循环?经过长时间的研究和与V8贡献者的讨论,我得到了以下概念。
libuv只提供了一个事件循环,V8只是一个JS运行时引擎。