将 JavaScript 嵌入到 Rust 中,并在 WebAssembly 中运行
WasmEdge 将 Rust 强大的性能和 JavaScript 的简单易用完美结合在一起
在我之前的文章中,我讨论了如何在 WebAssembly 沙箱中运行 JavaScript 程序。 WasmEdge runtime 为云原生 JavaScript 应用程序提供了一个轻量级、高性能且符合 OCI 标准的“容器”。
然而,JavaScript 是一种“慢”语言。使用 JavaScript 的原因主要是因为它用起来很容易,开发者生产力高,对初学者来说尤其如此。另一方面,WebAssembly 能够运行用 Rust 等语言编写的高性能应用程序。有没有结合 JavaScript 和 Rust 的解决方案? WasmEdge 给出了两全其美的答案。
有了 WasmEdge 和 QuickJS,开发者就可以完美搭配这两个最强大的语言来创造应用程序。就像下面这样:
- 该应用程序本身是用 Rust 写的并被编译成了 WebAssembly。它可以作为单个 wasm 字节码文件进行编译和部署。 它可以由符合 OCI 的容器工具管理,如 Docker Hub、CRI-O 和 k8s。
- JavaScript 程序嵌入在 Rust 应用程序中。 Rust 程序可以在编译时包含JavaScript 源代码,也可以在 runtime 通过文件、STDIN、网络请求甚至函数调用引入JS。 这样一来 JavaScript 程序可以由与Rust 程序不同的开发者编写。
- Rust 程序可以处理应用程序中的计算密集型任务,而 JavaScript 程序可以处理“业务逻辑”。 例如,Rust 程序可以为 JavaScript 程序准备数据。
接下来,让我们看几个示例。所有示例都在 wasmedge-quickjs repo 的 embed_in_rust
分支中。
$ git clone https://github.com/second-state/wasmedge-quickjs $ git checkout embed_in_rust
确保你已经安装 Rust 和 WasmEdge,这样才能构建和运行本文中的示例。
Hello WasmEdge
main.rs 中的以下 Rust 程序在编译时嵌入了一个 JavaScript 程序。
pub mod quickjs_sys; ... ... fn main() { use quickjs_sys as q; let mut ctx = q::Context::new(); // include js code let code = include_str!("../example_js/demo.js"); // get args and set into quickjs let mut res_args = args_parse(); res_args.insert(0, "<embedded_no_filename>".to_string()); ctx.put_args(res_args); // run js code ctx.eval_str(code, ""); }
example_js/demo.js 代码如下。
import * as std from 'std'; print('hello') print('args:',...args) //write fs let wf = std.open('demo.txt','w') wf.puts('hello quickjs') wf.close() //read fs let rf = std.open('demo.txt','r') let r = rf.getline() print(r) rf.close()
你可以将 Rust + JavaScript 应用程序构建到单个 WebAssembly 字节码程序中。
$ cargo build --target wasm32-wasi --release
运行它,就看到打印到控制台的结果了。
$ cd example_js $ wasmedge --dir .:. ../target/wasm32-wasi/release/quickjs-rs-wasi.wasm
就是这样。 Rust 代码可以通过传递参数甚至直接修改包含的 JavaScript 源代码,将数据传递到 JavaScript 代码中。 JavaScript 代码还可以通过写入临时文件来返回值。
使用嵌入式 JavaScript 进行图片识别
你可以修改 main.rs 中的 Rust 程序以嵌入不同的 JavaScript 程序。 在下面的示例中,让我们更改为
`pub mod quickjs_sys; ... ... fn main() { ... ... let code = include_str!("../example_js/tensorflow_lite_demo/main.js"); ... ... ctx.eval_str(code, ""); }`
main.js 代码使用 WasmEdge Tensorflow 扩展的 JavaScript API 来调用 ImageNet 读取和识别图像模型。
import {TensorflowLiteSession} from 'tensorflow_lite' import {Image} from 'image' let img = new Image('./example_js/tensorflow_lite_demo/food.jpg') let img_rgb = img.to_rgb().resize(192,192) let rgb_pix = img_rgb.pixels() let session = new TensorflowLiteSession('./example_js/tensorflow_lite_demo/lite-model_aiy_vision_classifier_food_V1_1.tflite') session.add_input('input',rgb_pix) session.run() let output = session.get_output('MobilenetV1/Predictions/Softmax'); let output_view = new Uint8Array(output) let max = 0; let max_idx = 0; for (var i in output_view){ let v = output_view[i] if(v>max){ max = v; max_idx = i; } } print('label index:',max_idx,'\nconfidence:',max/255)
你可以将 Rust + JavaScript 应用程序构建到单个 WebAssembly 字节码程序中。 注意 --features=tensorflow
标志,它要求 Rust 编译器使用 WasmEdge TensorFlow 扩展 API。
$ cargo build --target wasm32-wasi --release --features=tensorflow
运行并查看打印到控制台的结果。
$ cd example_js/tensorflow_lite_demo $ wasmedge --dir .:. ../../target/wasm32-wasi/release/quickjs-rs-wasi.wasm
运行地更快
运行上面的 Tensorflow 推理示例需要花费 1-2 秒。这在 Web 应用场景中是可以接受的,但还能改进。在上篇文章中,我们提过由于其 AOT(提前编译器)优化,WasmEdge 是当前速度最快的 WebAssembly runtime。 WasmEdge 提供了一个 wasmedgec
实用程序来将 wasm
文件编译为原生的 so
共享库。你可以使用 wasmedge
来运行 so
文件而不是 wasm
文件以获得更快的性能。
下面的例子使用了 wasmedge
和 wasmedgec
的扩展版本来支持 WasmEdge Tensorflow 扩展。
$ cd example_js/tensorflow_lite_demo $ wasmedgec-tensorflow ../../target/wasm32-wasi/release/quickjs-rs-wasi.wasm quickjs-rs-wasi.so $ wasmedge-tensorflow-lite --dir .:. quickjs-rs-wasi.so
你可以看到图像分类任务可以在 0.1 秒内完成。这至少是 10 倍的改进!
so
共享库不能跨机器和操作系统移植。你必须在你部署和运行应用程序的机器上运行wasmedec
和wasmedec-tensorflow
。
下一步
在 Rust 中嵌入 JavaScript 是一种创建高性能云原生应用程序的强大方法。 下一篇文章中,我们将研究另一种技术方法:在 JavaScript 中嵌入原生库。
云原生 WebAssembly 中的 JavaScript 是下一代云和边缘计算基础设施中的新兴领域。 我们也是刚刚起步! 如果你也感兴趣,请加入我们的 WasmEdge 项目或通过提出 feature request issue 告诉我们,你需要的是什么。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
加密的艺术
加密算法最早诞生在什么时候?计算机出现之后吗?不,早在公元前 7 世纪,古希腊人就已经在使用加密算法了。他们使用一根叫 scytale 的棍子来传递加密信息,加密时先绕棍子卷一张纸条,把信息沿棒水平方向写,写一个字旋转一下,直到写完。解下来后,纸条上的文字消息杂乱无章,这就是密文。将它绕在另一个同等尺寸的棒子上后,就能看到原始的消息。如果不知道棍子的粗细,就无法解密里面的内容。 加密方式发展到今天,相比 scytale 的简单原理已经有了无法想象的巨大发展,我们现在基于更复杂的数学过程,即更为复杂的算法来进行加密。许多使用现代手段创建的成熟密码系统基本被认为是不可破解的。一个不可被破解的加密方式到底有多复杂?下面我们就来领略一下。 什么是加密? 我们通常所说的加密是指使用密钥将纯文本转换为难以理解的序列的方法,通常由两个基本部分构成:算法和密钥。 算法是将普通的文本(或者可以理解的信息)与一串数字(密钥)的结合,产生不可理解的密文的步骤,密钥是用来对数据进行编码和解码的一种算法。加密可以描述为一种方法,通过该方法,明文和密钥通过密码算法,产生秘密文本。 在期望的情况下,加密文本的内容只...
- 下一篇
解密秒杀系统架构,不是所有的系统都能做秒杀!
摘要:教你如何设计一个秒杀系统架构:从电商系统架构到秒杀系统、从高并发“黑科技”与致胜奇招到服务器硬件优化,全方位立体掌握秒杀系统架构!! 本文分享自华为云社区《实践出真知:全网最强秒杀系统架构解密,不是所有的秒杀都是秒杀!!》,作者: 冰 河。 电商系统架构 在电商领域,存在着典型的秒杀业务场景,那何谓秒杀场景呢。简单的来说就是一件商品的购买人数远远大于这件商品的库存,而且这件商品在很短的时间内就会被抢购一空。 比如每年的618、双11大促,小米新品促销等业务场景,就是典型的秒杀业务场景。 我们可以将电商系统的架构简化成下图所示。 由图所示,我们可以简单的将电商系统的核心层分为:负载均衡层、应用层和持久层。接下来,我们就预估下每一层的并发量。 假如负载均衡层使用的是高性能的Nginx,则我们可以预估Nginx最大的并发度为:10W+,这里是以万为单位。 假设应用层我们使用的是Tomcat,而Tomcat的最大并发度可以预估为800左右,这里是以百为单位。 假设持久层的缓存使用的是Redis,数据库使用的是MySQL,MySQL的最大并发度可以预估为1000左右,以千为单位。Redis...
相关文章
文章评论
共有0条评论来说两句吧...