Nodejs crypto 里的部分加解密函数为啥是同步的?
Nodejs crypto 里的部分加解密函数为啥是同步的?
比如 crypto.publicEncrypt 、 crypto.privateDecrypt ,这种比较耗时的函数为啥是同步的而不是异步回调?不会卡住整个进程么万一调用的次数比较多的话
问题是 nodejs 是多线程的吗?
linux 系统调用也大多是同步的
为什么要异步。。?加密解密本来就是 CPU 运算,又不是 IO ,有等待, CPU 空闲出来了,所以做成异步,让 CPU 做别的事情去。。。加解密的时候 CPU 本来就没空闲,难道将加密解密的运算派发到别的并行线程去做,强行做成异步的?这样有啥好处?又不能提高整个系统的吞吐量。
何为卡主整个进程?如果因为 IO 之类的等待,整个执行过程被挂起,这个才叫卡住了。加解密的时候执行线程就一直在运算,何来卡主整个进程而言。?
(感觉楼主还需要学习一些基本概念)
想明白了, CPU 密集运算确实不需要异步
node.js 是真是多线程的,你可以 ps -eL 看一下。异步磁盘 IO, 应该用多线程模拟的吧
其实强行做成异步也不是不行。
照你这么说为啥从 redis 取数据要做成异步的?
crypto.pbkdf2 是异步的
异步的用着麻烦,而且增加函数调用的开销。同步的当然会影响性能
所以有个权衡的,所以 pbkdf2 还有个 pbkdf2Sync ,让用户根据情况选择用不用异步
这事和是不是 CPU 密集根本没有关系
redis 这个例子的确不对
其实 crypto 里到处都是 CPU 密集的异步的例子, Cipher 、 Hash 之类的
看了下文档, hash 是同步啊, crypto 里只有 crypto.pbkdf2(password, salt, iterations, keylen, digest, callback)和 crypto.randomBytes(size[, callback])是异步
hash 支持 stream 接口,这算是异步了吧。不过 CPU 密集用异步确实没意义,徒增开销。
我觉得还是有意义的,新开一个 worker ,把计算任务丢进去,发挥多核优势?
终于有人提了…随便用一下 hash / hmac / Cipher / Decipher 都会 stop the world …
对于服务端能容忍么…不能哎
如果是 pure js 实现的话,同步无可厚非。。如果是 c/c++的话,交给 worker thread 回调貌似更好一点。很多计算也不一定能用到多核,如果能够不影响 v8 线程感觉也是不错的,毕竟处理器不仅仅有(完全空闲,完全占满) 2 种状态。不过具体的就不知道了。。
“不能再同意更多”
我猜同步的那几个 api 是将任务下发给底层 c++,然后 js 运行时的线程阻塞等待底层加密的结果,而异步 api 不会造成 js 线程的阻塞。
仔细想了下, cpu 密集运算异步也是有意义的,假如有个 cpu 密集运算函数,在同步下要耗时 1000ms ,同时会 stop the world ,在异步下要耗时 1500ms ,但可以把 cpu 分给其他任务使用,那我宁愿选择后者,毕竟假如没有其他任务的时候,异步耗时也只会有 1050ms
所以关键还是是否多线程啊,多线程才能利用到多核
这里不谈多核问题,这和单核多核没关系,就算单核,我也是愿意让 cpu 运算函数执行时间变长,把 cpu 时间分给其他任务
那也需要多线程,否则也做不到你说的"让 cpu 运算函数执行时间变长,把 cpu 时间分给其他任务"
需要开新线程跑 cpu 密集型任务
如果因为 IO 之类的等待,整个执行过程被挂起,这个才叫卡住了。加解密的时候执行线程就一直在运算,何来卡主整个进程而言。?
你就把加解密一直在运算当做等待好了,那不就是卡住了整个进程么?我希望能异步运算,这样就还能处理其他任务,就算会降低性能,我仍然希望如此
可不可以把异步假设为"开新线程来执行"?我不懂 nodejs 的异步原理,刚学,说到底 nodejs 不适合干这种活,我还是用其他的方法来加解密吧
异步不一定非要开新线程,但是 cpu 密集型的你不开新线程做的话 效果跟同步是一样的
这个跟语言没关系,因为一个 cpu 核同时只能跑一个线程
充分利用系统资源,提高真个系统吞吐量, node 的并行是通过多进程来实现的, libuv 确实也有多线程,但是这只是为了做磁盘 IO 做的(印象中好像还有 DNS 的一些操作),而不是用来跑任务,用并行多线程确实可以将运算交给另外一个线程,这样来做成异步的,但是 node 的多线程可不是为了这个存在的。
对于纯异步,多进程的系统,例如 nodejs ,单个进程中再引入并行的多线程来执行 CPU 运算,并不能提高系统的吞吐量,反而会引入其他的问题,对于负载很高的时候,更应该做的是如何将各个任务分布到各个 worker 进程来做,从而利用 CPU 资源。
也有多进程的系统也引入了多线程,例如 Nginx 之类的,但是他们的 IOLoop 和主逻辑也还是在同一个线程中执行的,这些引入的其他线程更多的是为隔离上层代码的阻塞,例如 Nginx 去同步的请求外部的系统,上层一些逻辑不得不阻塞, upstream 配套起来用。
上面很多说的通过开多个线程,提高系统性能啥的,这个不是 Node 的系统模型,而是 Java 环境下的模型,人家是单进程多线程。
而且正确的实现多线程程序不是那么简单事情, jvm 上面发展了很多年才有的现在强大的内存,并发模型,各种优秀的并行库和组件,这些方面 nodejs 还差的很远。。。
你就扯吧…还多进程…IOCP 和 epoll 被你吃了?
你确定我在扯? epoll 或者 kqueue 或者 iocp 是 ioloop 的实现基础,他们跟多进程多线程是同一个维度的东西。。?知道几个东西的名字就能上来装逼了?成本这么低。?不要上来就喷,把这些基础知识搞清楚了再说吧。。。
你清楚 libevent , libev , libuv , nginx , netty , gevent 这些东西的 io 模型或者说并发模型?如果你懂的话,你可以喷。。。。如果你狗屁不通,上来就喷,那你跟 sb 喷子有啥区别。。?不过看你这个帖子的回复,我觉得你不懂,如果你懂的话,你是不会有这么弱智的回复的。
对的对的这些模型全是靠多进程的,和多线程没什么事!你说的好!
我说过 nodejs 靠多进程实现非阻塞 IO ?什么叫并行,什么叫并发?我说的是 nodejs 要实现并行应该是通过多进程来做,通过多进程来充分利用系统资源。
进程线程跟 epoll 这些玩意是同一个维度的东西。。?我能说你这是恶意乱说我的意思。?或者说你根本就没看懂我的回帖的意思。
要通过线程来实现并行计算,提高系统的计算能力,那不是 nodejs 要做的事情, nodejs 现在的框架基础也不支持这些东西,因为他根本就没有成熟的并行环境下的内存模型, java 那么多同步组件是吃白饭的,线程级别的并行也不是简简单单加个锁这么简单的事情,除了同步,还有内存可见性之类的问题。。。对于同一个数据域,在并行线程环境下,两个线程可能看到的是不同的值,这些都需要同步与内存模型来保证不会出现这种问题。 node 的框架基础根本就没有提供这些东西,因为 node 本身根本就没有想过要提供线程级别的并行,而是让系统做成多进程,这也是为什么大家说 node 不适合 CPU 运算要求特别高的任务,其实这里还少了一点东西,那就是 CPU 运算要求特别高而且业务功能模块交互比较频繁的任务不适合 node ,单纯 cpu 密集型的任务用 node 来做没问题,多开进程就行,只要各个任务之间都是独立的,交互很少。
node 要强行实现线程并行也可以的, c++的 boost 库也有很多并行组件可用,但是这已经脱离的 nodejs 范畴。
你这明明什么都不懂,和稀泥有意思?
你俩都不是一个 LEVEL 的,去喝茶 CODING 吧,别浪费时间了,你意思懂的人都懂
讨论了那么多,还是都搞清楚 node 运行在哪里,搞清楚为啥 node 叫单进程单线程,就先看看 v8
在Node.js的crypto
模块中,部分加解密函数被设计为同步的,这主要是出于以下几个原因:
-
简单性:同步函数对于简单的、短时间的操作来说,代码更加简洁明了,不需要处理回调或Promise,降低了学习曲线和使用难度。
-
性能考虑:对于小规模的加解密任务,同步操作可能减少上下文切换和回调机制带来的额外开销,从而提高性能。
-
历史原因:Node.js早期版本在设计时,同步API更为普遍,随着异步编程模式的推广,虽然增加了异步版本,但同步版本依然保留以满足不同需求。
-
使用场景:在某些场景下,比如启动脚本或初始化配置时,使用同步API可以更方便地处理加解密操作,而无需担心异步带来的复杂性。
示例代码展示了同步和异步API的使用:
const crypto = require('crypto');
// 同步加密
const cipher = crypto.createCipher('aes-256-cbc', 'secret key');
let encrypted = cipher.update('some clear text data', 'utf8', 'hex');
encrypted += cipher.final('hex');
console.log(encrypted);
// 异步加密(使用Promise)
function encryptAsync(text, algorithm, key) {
return new Promise((resolve, reject) => {
const cipher = crypto.createCipher(algorithm, key);
let encrypted = cipher.update(text, 'utf8', 'hex');
encrypted += cipher.final('hex');
resolve(encrypted);
});
}
encryptAsync('some clear text data', 'aes-256-cbc', 'secret key').then(console.log);
在实际应用中,选择同步还是异步API应根据具体需求和性能考量来决定。