当前位置: 首页 > 后端技术 > Node.js

Napa.js简介

时间:2023-04-03 22:52:55 Node.js

原文地址:https://github.com/Microsoft/...本文介绍了Napa.js的核心概念,带领大家探索Napa.js的工作原理。关于它的由来和开发初衷,可以看这篇文章简介ZoneZone是Napa.js中的核心概念,是执行JavaScript代码的基本单位,所有涉及到多线程的内容都离不开这个概念区。一个进程可以包含多个区域,每个区域由多个JavaScriptWorker组成。区域内的所有工作人员都是相似的:它们加载相同的代码,以几乎相同的方式处理广播和执行请求,并且您无法指定在特定工作人员中执行哪些代码。不同Zone中的Worker是完全不同的:他们加载不同的代码,或者他们加载相同的代码但执行不同的策略,例如不同的堆栈大小、不同的安全策略等。应用程序将利用多个Zone来加载不同的策略。有两种类型的区域:Napa区域-由多个由Napa.js管理的JavaScriptworker组成。Napa专区中的Worker支持部分Node.jsAPINode专区——一个公开Node.js事件循环并具有完整Node.js功能的虚拟专区。这个划分可以让你使用Napazone来处理重计算事务,也可以使用Nodezone来处理IO事务。同时,Node专区也是对Napa专区无法全面支持NodeAPI的补充。以下代码创建了一个有8个工作人员的Napa区域:varnapa=require('napajs');varzone=napa.zone.create('sample-zone',{workers:8});以下代码演示了如何访问节点区域:varzone=napa.zone.node;可以在区域上执行两种类型的操作:广播-所有工作人员执行相同的代码,更改工作人员状态,并返回承诺对象。但是,我们只能通过promise的返回结果来判断执行成功与否。通常广播用于启动应用程序、预加载一些数据或修改应用程序设置。执行-在随机工作人员上执行,不更改工作人员状态,返回包含结果数据的承诺。execute通常用于做实际业务。Zone的运行采用“先进先出”的策略,但广播的优先级高于执行。下面的代码演示了使用broadcast和execute来完成一个简单的任务:functionfoo(){console.log('hi');}//这会在zone.zone.broadcast(foo.toString());//在任意worker.zone.execute(()=>{global.foo()})上执行foo函数;数据传输由于V8不适合在多个isolate之间执行JavaScript代码,因此每个isolate管理自己的内部堆栈。isolate之间传值需要编组/解组,payload的大小和对象的复杂程度决定了通信效率。所有的JavaScriptisolate都属于同一个进程,原生对象可以打包成JavaScript对象。基于此,我们尝试为Napa设计一种高效的数据传输方式。为了实现上述模式,引入了以下概念:TransportableTypesTransportabletypes是可以在worker之间自由传输的JavaScript类型。包括JavaScript基本类型:null、boolean、number、string实现了Transportable接口的对象(TypeScript类),由上述类型组成的数组或对象,以及未定义的inter-worker存储StoreAPI,用于在JavaScriptworker之间共享数据。store.set执行时,数据被编组为JSON并存储在进程的堆栈中,所有线程都可以访问该堆栈;当执行store.get时,数据被解包。下面的代码演示了如何使用store来共享数据://在node.store.set('key1',{a:1,b:"2",c:napa.memory.crtAllocator//transportablecomplextype.};//Get'key1'in另一个线程。zone.execute(()=>{varstore=global.napa.store.get('store1');console.log(store.get('key1'));});虽然方便,但是不建议在同一个事务中使用Usestore传值,因为它不仅仅是传递数据(还包括其他的东西,比如加锁)。另外,虽然有垃圾回收机制,但是开发者应该手动删除相应的key,安装执行npminstallnapajs安装,OSX系统安装后会报错,githubissue中也有同样的问题,解决办法是根据官方build文档手动build。最新版本v0.1.4已经发布修复以上问题。步骤如下:安装先决条件安装支持C++14的C++编译器:xcode-select--installInstallCMake:brewinstallcmakeInstallcmake-js:npminstall-gcmake-js通过npmnpminstall--no-fetch构建快速入门示例计算pi的π值下面是一个计算π值的例子,演示了如何使用多线程执行子任务。varnapa=require("napajs");//更改此值以控制已初始化的napaworker的数量。constNUMBER_OF_WORKERS=4;//创建一个带有number_of_workers的napazonenapaworkers.varzone=napa.zone.create('zone',{workers:NUMBER_OF_WORKERS});//使用蒙特卡罗方法估计π的值functionestimatePI(points){vari=points;内部变量=0;while(i-->0){varx=Math.random();vary=Math.random();如果((x*x)+(y*y)<=1){里面++;}}returninside/points*4;}functionrun(points,batches){varstart=Date.now();}var承诺=[];for(vari=0;i{varaggregate=0;values.forEach(result=>aggregate+=result.value);printResult(points,batches,aggregate/batches,Date.now()-开始);});}functionprintResult(points,batches,pi,ms){console.log('\t'+points+'\t\t'+batches+'\t\t'+NUMBER_OF_WORKERS+'\t\t'+ms+'\t\t'+pi.toPrecision(7)+'\t'+Math.abs(pi-Math.PI).toPrecision(7));}console.log();console.log('\t#点\t#批次\t#workers\tlatencyinMS\testtimatedπ\tdeviation');console.log('\t-------------------------------------------------------------------------------------');//按顺序运行不同数量的点和批次。run(4000000,1).then(result=>run(4000000,2)).then(result=>run(4000000,4)).then(result=>run(4000000,8))结果如下,当设置为1组时,2组时,并并行计算4组子任务,可以看出执行时间有了明显的提升。当设置为8组子任务并行计算时,由于没有更多的空闲worker资源,执行时间没有明显提升#ofpoints#ofbatches#MS中的工人延迟估计π偏差-----------------------------------------------------------------------------------400000001410153.1416190.000026646464140000000245323.1413480.000245053640000000443313.1411850.0004040805364000000initialized.constNUMBER_OF_WORKERS=4;//用number_of_workers创建一个napazone01234567891011...----------------------------------------------------------------------NTH斐波纳契:|01123581321345589...*/函数fibonacci(n){如果(n<=1){返回n;}varp1=zone.execute("","斐波那契",[n-1]);varp2=zone.execute("","斐波那契",[n-2]);//返回promise以避免阻塞每个worker。returnPromise.all([p1,p2]).then(([result1,result2])=>{returnresult1.value+result2.value;});}functionrun(n){varstart=Date.now();returnzone.execute('',"fibonacci",[n]).then(result=>{printResult(n,result.value,Date.now()-start);returnresult.value;});}函数printResult(nth,fibonacci,ms){console.log('\t'+nth+'\t'+fibonacci+'\t\t'+NUMBER_OF_WORKERS+'\t\t'+ms);}console.log();console.log('\tNth\tFibonacci\t#ofworkers\tlatencyinMS');console.log('\t----------------------------------------------------------');//'napa的广播声明'和'zone'到napaworkers.zone.broadcast('\varnapa=require("napajs");\varzone=napa.zone.get("zone");\');//向napaworkers.zone.broadcast(fibonacci.toString());//运行'fibonacci'广播函数声明sequence.run(10).then(result=>{run(11).then(result=>{run(12).then(result=>{run(13).then(result=>{run(14).then(result=>{run(15).then(result=>{run(16)})})})})})})运算结果NthFibonacci#ofworkerslatencyinMS-------------------------------------------------------105541011894131214441513233422143774311561045016987481