Napa.js简介

来源:互联网 发布:淘宝可以多久确认收货 编辑:程序博客网 时间:2024/06/05 21:00

原文链接:https://github.com/Microsoft/napajs/wiki/introduction

介绍

该文章介绍的概念对于理解Napa.js如何工作非常重要。想了解它的起源可以读这篇文章。

Zone

在Napa.js中,与多线程相关的工作都围绕Zone概念展开,它是定义策略和执行JavaScript代码的基本单元。一个程序包含多个zone,每一个zone包含多个JavaScript worker。


在一个zone中,所有的worker都是相等的的:它们以相同的方式加载同样的代码、为broadcast和execute请求服务。基本上,你无法指定zone中一个特定的worker来执行代码。不同zone之间的worker是不相等的:它们加载不同的代码,或者即使加载相同的代码也会使用不同的策略,比如堆的大小、安全策略的配置等。应用需要多个zone来完成不同目的或者不同策略的工作负载。

有两种类型的zone:

  • Napa zone - 由管理JavaScript workers(V8隔离)的Napa.js组成的zone。Napa zone可以有多个,每个zone包含多个worker。Napa zone的worker支持部分的Node.JS APIs。
  • Node zone - 一个暴露了 Node.js event loop 的虚拟 zone,它支持全部的Node.js的功能。

这种方式使你能够使用Napa zone来做繁重的计算任务,同时使用Node zone 来操作IO事务。Node zone也弥补了Napa zone对Node APIs支持不完整的不足。

下面的代码创建了一个包含8个worker的Napa zone:

var napa = require('napajs');var zone = napa.zone.create('sample-zone', { workers: 8 });

下面的代码说明如何访问Node zone:

var zone = napa.zone.node;

在zone上可以执行两种操作:

  1. Broadcast - 在所有的worker上执行可以改变worker状态的代码,返回一个promise对象。通过promise,我们仅能知道操作是否成功。通常,我们使用broadcast来启动应用程序、预加载对象或者改变应用设置。

  2. Execute - 在一个随机的worker上执行不会改变worker状态的程序,返回一个包含结果的promise。Execute 用于实现实际的的业务。

Zone的操作都是基于“先进先出”原则,而且broadcast拥有比execute更高的优先级。

下面的代码说明了如何使用broadcast和execute来完成一个简单的任务:

function foo() {   console.log('hi');}// This setups function definition of foo in all workers in the zone.zone.broadcast(foo.toString());// This execute function foo on an arbitrary worker.zone.execute(() => { global.foo() });

数据传递

V8不是被设计用于在多个isolate之间执行JavaScript程序,也就意味着每个isolate管理各自拥有的堆栈。从一个isolate到另一个isolate之间传递的数据必须被封装和解封(marshalled/unmarshalled)。有效载荷的大小和对象的复杂度对isolate间的通信效率影响很大。在Napa中,我们尝试找到一个可实现对象高效共享的设计模式,它是基于所有的JavaScript isolate(也就是worker)都位于相同的进程中,而且原生对象能够被封装成JavaScripts对象对外暴露。

下面是为了实现该设计模式而引入的概念:

Transportable types 可传递类型

可传递类型是JavaScript类型中可以在Napa worker间被显式地传递和分享的数据类型。它们作为值类型传递给broadcast和execute的入参,也通过set和get方法共享键值对对象。

可传递类型是:

  • JavaScript 原始类型:null,boolean,number,string
  • 实现了可传递接口的对象
  • 数组或由上述类型组成的简单JavaScript对象
  • undefined

跨worker存储

在通过参数传递数据方面,存储API的引入是对JavaScript worker 间共享可传递类型的必要补充。调用store.set,值按顺序以JSON的形式存入进程堆,因此所有的线程都可以访问它,而且用户可以通过调用store.get来得到这些值。

下面的代码展示了如何使用store来共享对象:

var napa = require('napajs');var zone = napa.zone.create('zone1');var store = napa.store.create('store1');// Set 'key1' in node.store.set('key1', {     a: 1,     b: "2",     c: napa.memory.crtAllocator      // transportable complex type.};// Get 'key1' in another thread.zone.execute(() => {    var store = global.napa.store.get('store1');    console.log(store.get('key1'));});

尽管非常方便,但是在事务处理和请求时不推荐使用存储,因为它的消耗比通常传参要大(会额外带着锁等信息)。此外,虽然有垃圾回收机制,但是开发者还应该在使用完后删除key。