Nodejs 一般都碰到把异步方法写成同步的样子,很少有人会想把同步方法写成异步。今天你就看到了。
事情是这样子的,之前写的哪个异或运行,我写成了一个服务了。本来 Nodejs 就对计算密集不擅长,现在运算还是同步的,要是请求多了,这服务就慢了。这怎么能忍呢?
把异或运算写成长得像异步方法(为什么说是长得像,下面你就知道了),其实有个很常见的办法,那就是setTimeout
,但是这次我选择process.nextTick
,要问我为什么选这个,我只能说我就是想玩点没玩过的东西。实例如下:
1 2 3 4 5 6 function foo ( ) { console .error ('foo' ); } process.nextTick (foo);console .error ('bar' );
那要是函数有参数的呢?
1 2 3 4 5 6 function foo (_, vlaue ) { console .error ("foo:" , vlaue); } process.nextTick (foo, 1 , 2 );console .error ("bar" );
或者更 hack 一点的写法
1 2 3 4 5 6 7 8 function foo (_, vlaue ) { return () => { console .error ("foo:" , vlaue); }; } process.nextTick (foo (1 , 2 ));console .error ("bar" );
这个 tick 涉及到事件轮训,深一点的一时半会我说不明白。这里引用 nodejs 中文网 的的话
每当事件循环进行一次完整的行程时,我们都将其称为一个 tick。
当将一个函数传给 process.nextTick() 时,则指示引擎在当前操作结束(在下一个事件循环滴答开始之前)时调用此函数
虽然我们看到上面的例子是先打印bar
后打印的foo
,但是真的是利用到了多核吗?做个实验
1 2 3 4 5 6 7 8 9 10 11 12 13 14 function foo (start, end ) { return () => { let result = start; for (let index = start + 1 ; index <= end; index++) { result += index; }; console .log (result); }; }foo (1 , 3 )(); process.nextTick (foo (1 , 200 )); process.nextTick (foo (1 , 2 ));console .log ("bar" );
然后运行
结果输出如下
1 2 3 4 5 6 bar 20100 3 node test.js 0.05s user 0.00s system 102% cpu 0.050 total
emmmm,怎么像是顺序执行的?这异步是假的?在网上找到一篇译文:理解 Node.js 里的 process.nextTick() ,里面有这么一个描述
当然,我们无法通过 process.nextTick() 来获得多 CPU 下并行执行的真正好处,这只是模拟同一个应用在 CPU 上分段执行而已。
所以process.nextTick()
根本利用不了多核,那怎么办?我又不想去碰 C++ addons (得承认是自己太菜写不了 C++)
其实还是有办法的,比如使用cluster
、Child process
,Worker threads
,这里就使用cluster
写个测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 function foo (start, end ) { let result = start; for (let index = start + 1 ; index <= end; index++) { result += index; }; return result; }const cluster = require ("cluster" );const numCPUs = require ("os" ).cpus ().length ;const min = 0 ;const max = 1e8 ; let primes = 0 ;if (cluster.isMaster ) { const range = Math .ceil ((max - min) / numCPUs); let start = min; for (let i = 0 ; i < numCPUs; i++) { const worker = cluster.fork (); worker.send ({ start : start, range : range }); start += range; worker.on ("message" , msg => { primes += msg.data ; worker.kill (); }); } cluster.on ("exit" , function (worker, code, signal ) { }); process.on ("exit" , () => { console .log ("primes " + primes); }); } else { process.on ("message" , msg => { const { start, range } = msg; const data = foo (start + 1 , start + range); process.send ({ data : data }); }); }
多核是用上了,是我例子写的太简单了吗?耗时还不如单核?下次研究。