HarmonyOS开发者限时福利来啦!最高10w+现金激励等你拿~ 了解详情
写点什么

JavaScript 如何应用在 IoT?

  • 2019-07-05
  • 本文字数:3921 字

    阅读完需:约 13 分钟

JavaScript如何应用在IoT?

在日前的 GMTC 全球大前端技术大会上,Rokid 基础平台研发中心的研发工程师刘亚中发表了《JavaScript in IoT》的演讲,本文整理内容如下。

什么是 IoT

如字面翻译,即物联网,但真正要解释起来,其实就是两点:



  • IoT 是面向服务的 UI。



  • IoT 面临资源受限的问题。



在物联网时代,我们不再像从前那样独立地使用某个固定、单一的产品,而是在享受着整个环境或者是网络给我们提供的服务,比如原来我们买一个闹钟回来,闹钟就是闹钟,在 IoT 环境下,闹钟是其中的一环,当它叫醒你后,整个系统会为你准备起床后需要的所有待办事物,这就是物联网。


接下来我们来看看资源受限的问题:



最右侧的手机自不必说,整个生态已经相当成熟了。最左侧的是目前的低端配置,可以看到内存和可用空间都是 MB 为单位的,CPU 也相当受限,因此这种设备上 Linux 也已经不满足运行的最低需求了,所以一般是采用更轻量级的 RTOS,流行的有 FreeRTOS 和 RT-Thread(国内)。


最中间的是以 Linux 为主的 128+128 组合的设备,最为我们所熟知的就是智能音箱(无屏),对于这类设备来说包括 Alexa、Rokid、小爱同学等,现在大多数厂商在设备端的开发语言也都以 C + Lua 为主,目前也仅有 Rokid 支持 JavaScript 直接运行在设备端,而本文也主要是针对智能音箱这一挡设备来展开。


然后我们来看下,为什么在 128 MB 的设备上运行 JavaScript 也如此困难呢?



上图是 Rokid 智能音箱上各个子模块的内存占用情况:



  • kernel 内核占用,用于保证 Linux 用户态程序能正常运行。



  • dsp 包括从麦克风读出语音数据,然后进行算法处理,最终获取是否语音激活。



  • system 包括一些底层系统功能,如 IPC 服务、多媒体服务、存储服务等。



  • applications 即上层应用的逻辑。



通过上图的比例最终可以看出,JavaScript 真正能用的内存只有 25MB,这对于目前一个 Node.js 进程来说也就刚刚好而已,这也是目前大多数音箱,仅在服务器上提供 JavaScript SDK 的原因。

Why JavaScript?

为什么我们要在 IoT 使用 JavaScript 呢?这里简单给出几个理由。首先 Web 已经是一个相当成熟的社区了,它聚集了大量的开发者,这对于任何一个开放平台来说,都是一个非常有吸引力的开发者来源。


另外得益于 JavaScript 或者说 Web 这种即时更新的机制,在解决设备碎片化问题上,有着天然的优势,因此对于 IoT 的碎片化问题,我们希望借助于 Web 来解决。


另外,Web 标准组织已经提出了 WOT —— Web of Things 的概念,因此对于我们来说,要做的就是跟标准组织一起推进 WOT 的落地,这也是一个非常顺理成章的事情。


如果你想参与更多前端技术交流,获取更多专家分享,可以加入我们的“前端技术交流群“,社群内会经常讨论前端相关的技术、分享免费学习资料,我们也会邀请前端专家进行社群分享、直播、公开课等活动。如果你感兴趣,欢迎添加社群管理员微信 GeekUni004,回复“前端群”申请入群。

ShadowNode —— Node.js on IoT

ShadowNode 截止目前为主,已经支持如下特性:



  1. 支持 macOS 与 Linux 的编译和运行。



  2. 支持 x86、arm 与 aarch64。



  3. 支持大部分核心的 Node.js API,如:assert / buffer / N-API Add-ons / child process / crypto / dns / events / file system / http / https / module / net / os / process / timers / TLS / UDP



  4. 支持了 WebSocket / MQTT 等流行的 IoT 库



  5. 支持 CPU 和 Heap 的 Profiler



  6. 支持 N-API



接下来,关于 ShadowNode 的历史大家可以去看之前的专栏文章:



简单来说呢,ShadowNode 就是为了能让 JavaScript 能愉快地跑在 IoT 设备上而存在的,下面是 ShadowNode 与 Node.js 的一些资源占用上的对比:



可以看出无论是 macOS 上,还是 ARM 上,ShadowNode 在内存占用上有明显地提升,还记得我们之前看到智能音箱上各子模块的内存分布吗?对于应用来说可用内存有 25MB,如果使用 ShadowNode 作为运行时的话,基本上就达到了可以随意新增本地应用的状态了。



然后是启动时间,对于设备端上的应用来说,往往为了省内存,会把不重要,或不再使用的应用(进程)杀掉,当有需要时,再重新启动,因此这对进程的启动时间,包括 CPU 占用都提出了不小的要求,可以看出 ShadowNode 在这方面的表现也优于 Node.js。

N-API on ShadowNode


N-API 作为 Node.js Add-on 的 ABI 兼容的接口,可以让任何程序在不需要重新编译的情况下无缝运行在 node-chakracore 与 node-v8 上,ShadowNode 同样如此,我们按照 N-API 的标准文档和测试集,实现了在 ShadowNode 上的 N-API,这样在不需要重新编译的情况下,也能在 Node.js 和 ShadowNode 跨运行时运行,这使得我们可以根据不同的设备配置,选择合适的运行时,而上层的代码则不需要任何修改。


ShadowNode 的 N-API 完全是基于 Node.js 仓库下的 N-API 测试用例测试的,除了一些我们还不支持的特性外,其余的测试用例都会在 ShadowNode CI 上做验证,所以对于稳定性方面大可放心使用。

性能

我们在 IoT 下,针对一些特定场景,也做了一些性能优化。


比如需要使用一些第三方仓库时,仓库本身太过臃肿,导致在设备上加载起来就已经很花时间了(ShadowNode 没有 JIT),甚至于大多数情况是加载不进来的,因为这些库会在堆里创建大量的对象,而 ShadowNode 有预置的 heap_maximum_size,这样难道就没有其他办法了吗?


后面我们想到了一个办法,那就是保持兼容这些第三方库的 JS API,底层全部用 C/C++ 重写,这样可以减少大量的对象创建,同时也能让开发者使用时没有任何差异,我们使用这种方式分别完成了 WebSocket 和 MQTT 在 ShadowNode 上的移植。


另外一个优化手段是引入 NODE_PRIORITIZED_PATH,大家肯定对 NODE_PATH 不陌生吧,那 NODE_PRIORITIZED_PATH 理解起来也不困难,就是一个最高优先级的 NODE_PATH。因为在 IoT 设备上的情况与服务端往往不同,Node.js 模块都是放在每个项目中的,然而在 IoT 设备上的每个应用都比较轻,因此大部分依赖库都是放在全局的 node_modules,这样就导致每次 require 时,总会从模块的当前路径去搜索,这样造成了大量的浪费。


因此我们引入了 NODE_PRIORITIZED_PATH 来设置为全局路径,这样帮我们节省了 30%的启动时间。


接下来是 Copy-on-Write 技术(以下简称 COW),它是 Linux 针对 fork 函数的优化方法,可以节省进程启动时间与内存。这里首先要科普一个知识,即 child_process.fork 并不是真正的 fork,他依然要让子进程从零开始执行,并且抛弃掉父进程的所有资源。


我们来看一下下面的代码:


function uv_spawn (file, args) {  var pid = fork()  if (pid === 0) {    execvp(file, args) *// this disables COW*    *// starting VM and load script*  }}uv_spawn(‘test.js’, [])
复制代码


在 Node.js 中,无论是 spawn、exec 还是 fork,都调用了同一个 uv_spawn 函数,以上是该函数的伪代码(JavaScript 版本)。可以看到每次 fork 完,都会在子进程调用 execvp 来重新初始化子进程,一旦使用了 execvp 这个函数,就意外着系统将把 COW 禁用了,我们再来看看不调用 execvp 的情况下,如何写代码:


var fork = require(‘linux-sys’).fork
*// load common modules for children*var player = require(‘player’)var http = require(‘http’)var foobar = require(‘foobar’)
*// start forking*var pid = fork()if (pid == 0) { *// here is the child process* *// use player / http / foobar*}
复制代码


上面的代码不再是伪代码了,我们通过将系统的 fork 使用 N-API 暴露给 JavaScript 层,然后从 fork 开始到子进程真正能使用 player、http 和 foobar 模块,仅花了 4ms。


当然,上面的示例代码只是为了证明 COW 拥有卓越的性能提升,因此我们后来就创建了一个新项目 —— Hive。


yodaos-project/hive:https://link.zhihu.com/?target=https%3A//github.com/yodaos-project/hive)


github.comhttps://link.zhihu.com/?target=https%3A//github.com/yodaos-project/hive)


Hive 是一个独立于 ShadowNode 的子项目,可以运行在 Node.js 与 ShadowNode 上,因此我们基于 Node.js,对 hive-fork、nodejs-fork、nodejs-spawn 做了一组对比测试:



我们得出的结论显而易见,Hive 在启动速度上几乎是完胜 child_process,这对于设备端的应用启动加速具有很大的意义。


同时在 FaaS 时代,我相信 Hive 也能占有一席之地,FaaS 典型的场景就是快速启动一个进程来执行,然后退出,使用 Hive 可以轻松地定义脚本中的 API,定义好之后,便不需要担心进程启动后所带来的加载消耗,因为几乎是 0 成本的。


YodaOS 从诞生的第一个版本,到现在已经快 1 年时间了。接下来小小预告一下,下半年我们准备发布第二个大版本,即 YodaOS 8.0。在这个版本中,YodaOS 与 Rokid 开放平台完成了解耦,本地的应用也采用了大家熟悉的 Web 应用(不完全兼容)。届时,开发者可以使用 YodaOS 来接入 Alexa、天猫精灵或者 Google Assistant。

总结

很开心能够参加 GMTC 这样的活动,不管是作为讲师还是听众,都收获颇多,我相信 JavaScript 一定会在 IoT 时代释放更多开发者的能量。

嘉宾介绍

刘亚中,开源爱好者,Node.js Collaborator、ShadowNode 作者,目前主攻:Node.js 在 AIoT 领域的应用, 并负责 YodaOS 的社区推广工作。五年 JavaScript 开发经验,曾就职于:SeedMail、Pixbi、阿里巴巴,目前就职于 Rokid 基础平台研发中心,主要工作方向为基于 JavaScript 的物联网操作系统。近年来参与并负责 YodaOS 项目,将 IoT 和 AI 能力开放给 Node.js 社区,并实现了 Node.js 在 IoT 场景的产品级落地。同时也是 Node.js Collaborator、ShadowNode 和 TensorFlow-Node.js 作者,开源发烧友,目前给 60 个开源项目贡献过代码。


2019-07-05 17:594959

评论

发布
暂无评论
发现更多内容

Spring 5(五)事务操作

浅辄

Spring5 事务 11月月更

灵雀云ACP 斩获“2022金边奖-最佳云原生边缘云平台”

York

容器 云原生 5G 边缘计算 边缘云

数据库精选 60 道面试题

钟奕礼

Java Java 面试 java程序员 java编程

MetaForce佛萨奇2.0系统开发DAPP搭建

薇電13242772558

dapp开发

Python图像处理丨5种图像处理特效

华为云开发者联盟

Python 人工智能 华为云 图像处理

首批招募 50 家!「龙腾社区生态发展计划」正式发布

OpenAnolis小助手

开源 操作系统 云栖大会 龙蜥社区 合作

RocketMQ 重试机制详解及最佳实践

阿里巴巴云原生

阿里云 RocketMQ 云原生

Dive into TensorFlow系列(3)- 揭开Tensor的神秘面纱

京东科技开发者

Python 人工智能 深度学习 tensorflow

Wallys/ WiFi6 MiniPCIe Module 2T2R 2×2.4GHz 2x5GHz MT7915 MT7975 /industrial mini pcie card

wallysSK

MT7915

5种GaussDB ETCD服务异常实例分析处理

华为云开发者联盟

数据库 后端 华为云

AOP 的九点核心概念和作用

千锋IT教育

微服务中的服务发现是什么?

API7.ai 技术团队

微服务 服务发现 API网关 APISIX

【LeetCode】统计匹配检索规则的物品数量Java题解

Albert

算法 LeetCode 11月月更

阿里P8出,入职阿里必会199道SpringCloud面试题,你能掌握多少?

钟奕礼

Java java程序员 java面试 java编程

深究并行编程Parallel类中的三大方法 (For、ForEach、Invoke)和几大编程模型(SPM、APM、EAP、TAP)

C++后台开发

多线程 后端开发 linux开发 C++开发 并行编程

大数据培训学习需要什么基础

小谷哥

消息队列 RocketMQ 5.0:从消息服务到云原生事件流平台

阿里巴巴云原生

阿里云 RocketMQ 云原生

软件测试 | 测试开发 | 校招面试真题 | 实习生和应届生有什么区别?

测吧(北京)科技有限公司

软件测试 软件测试工程师

成为千行百业数字化转型催化剂的,竟然是它!

元年技术洞察

微服务 低代码 数字化转型

声网深度学习时序编码器的资源预测实践丨Dev for Dev 专栏

声网

深度学习 算法 模型

腾讯T4带你玩转Spring全家桶

钟奕礼

Java java程序员 java面试 java编程

低门槛上手快!火山引擎VeDI这样满足数据分析新需求

字节跳动数据平台

大数据 BI

Meta Force 原力元宇宙公排系统开发详情

开发微hkkf5566

大数据培训和自学哪种方式更好

小谷哥

学历不是问题!社招大专老哥阿里 腾讯Java面试,上岸入职京东

钟奕礼

java程序员 java面试 java编程 #java

使用 Fiori Elements 框架创建 UI5 Web 应用

汪子熙

web开发 Fiori SAP UI5 ui5 11月月更

离职、被毕业?职场打工人的最强生存指南!

千锋IT教育

PolarDB-X 开源分布式数据库进阶营免费报名中!

阿里云数据库开源

MySQL 数据库 阿里云 开源 PolarDB-X

PCB设计必须考虑的8种安全距离,搞错1种都出大问题!

华秋PCB

PCB PCB设计

极客时间架构训练营模块六作业

李晨

架构

终于有人把这份10 万字节详细面试笔记(带完整目录) 整理出来了

钟奕礼

Java java程序员 java面试 java编程 Java 面试题

JavaScript如何应用在IoT?_语言 & 开发_刘亚中_InfoQ精选文章