如何在 Deno 应用程序中调用 Rust 函数

栏目: IT技术 · 发布时间: 5年前

内容简介:作者:Michael Yuan原文链接:如何在 Deno TypeScript 应用程序访问 Rust 函数?

作者:Michael Yuan

原文链接: https://www.infoq.com/article...

如何在 Deno TypeScript 应用程序访问 Rust 函数?

如何在 Deno 应用程序中调用 Rust 函数

要点:

  • Deno 和 Node.js 都在基于 C/C ++ 的运行时上执行 JavaScript 以实现高性能。
  • Deno 是单个二进制应用程序,与 NPM 模块不兼容,并且没有简单的方法能将本机模块合并到应用程序中。
  • WebAssembly 提供了一种在 Deno 应用程序中运行高性能代码的方法。
  • WebAssembly 用于服务端应用程序,是安全、轻便且轻量级的容器。
  • Rust 编译器 工具 链为 WebAssembly 提供了强大的支持。

备受期待的 Deno 项目不久前发布了 1.0 版本。 Deno 由 Node.js 的创建者之一 Ryan Dahl 发起,解决 Ryan 所认为的“我为 Node.js 感到遗憾的十件事”。

Deno 没有采用 NPM 和臭名昭著的 node_modules 。 Deno 是一个单一的二进制可执行文件,运行用 TypeScript 和 JavaScript 编写的应用程序。

但是,尽管 TypeScript 和 JavaScript 适用于大多数的 Web 应用程序,但它们不能满足计算密集型任务,例如神经网络训练和推理、机器学习和密码学。 实际上,Node.js 经常需要使用本地库来执行这些任务(例如,使用 openssl 进行加密)。

如果没有类似 NPM 的系统来合并本机模块,我们如何在 Deno 上编写需要本机性能的服务端应用程序呢? WebAssembly 将提供帮助! 在本文中,我们用 Rust 编写高性能函数,将 Rust 函数编译为 WebAssembly,然后在 Deno 应用程序中运行它们。

TL;DR

在 GitHub 上 clone 或者 fork Deno starter 模板 。按照下面的说明进行操作,只需5分钟,就可以在 Deno 中运行 WebAssembly 函数(由 Rust 编写)。

背景知识

Node.js 之所以非常成功,是因为它为开发人员带来了两全其美的优势:JavaScript 的易用性(尤其是基于事件的异步应用程序)以及 C/C ++ 的高性能。 Node.js 应用程序是用 JavaScript 编写的,但是在基于 C / C ++ 的本机运行时中执行,例如,Google V8 JavaScript 引擎和许多本机库模块。 Deno 希望复制此公式以取得成功,但不同的是,Deno 用 TypeScript 和 Rust 支持现代技术堆栈。

Deno 是用 Rust 编写的,基于 V8 的 JavaScript 和 TypeScript 的简单、现代且安全的运行时。 -deno.land网站。

《我对 Node.js 感到遗憾的十件事 》这个著名演讲中,Node.js 的创建者 Ryan Dahl 解释了为什么要开始 Deno 并将 Deno 看做 Node.js 的竞争对手甚至替代者。Dahl 的遗憾集中在 Node.js 如何管理第三方代码和模块上。

  • 用于将 C 模块连接到 Node.js 的复杂构建系统。
  • package.jsonnode_modulesindex.js 以及其他 NPM 工件非常复杂,但是这并不是必须的。

因此,Deno 在管理依赖项时做出了一些非常有意识和自觉的选择。

 import

这很好。但是,需要更高性能的应用程序应该怎么做呢?特别是需要在几秒钟之内执行复杂的神经网络模型的AI即服务应用程序,该如何处理呢? 在 Deno 和 Node.js 中,许多函数都是通过 TypeScript 或 JavaScript API 调用的,但是这些函数都是在用 Rust 或 C 语言编写的本机代码执行。在 Node.js 中,始终可以选择从 JavaScript API 调用第三方的本地库。 但是我们目前无法在 Deno 中执行此操作吗?

Deno 中的 WebAssembly 支持

WebAssembly 是一种轻量级虚拟机,旨在以接近本机的速度执行可移植的字节码。你可以将 Rust 或 C C ++ 函数编译为WebAssembly 字节码,然后从 TypeScript 访问这些函数。对于某些任务,这种方式比执行 TypeScript 编写的等效函数要快得多。例如,IBM 发布的研究发现在某些数据处理算法中使用 Rust 和 WebAssembly ,可以将 Node.js 的执行速度提高 1200% 至 1500% 。

Deno 内部使用 Google V8 引擎。 V8 不仅是 JavaScript 运行时,还是 WebAssembly 虚拟机。 Deno 开箱即用地支持WebAssembly。 Deno 为 TypeScript 应用程序提供了一个API,以调用 WebAssembly 中的函数。

实际上,WebAssembly 中已经实现了一些流行的 Deno 组件。例如,使用 Emscripten 将 sqlite 的 C 源代码编译到 WebAssembly 中来创建 Deno 中的 sqlite 模块Deno WASI 组件 使 WebAssembly 应用程序可以访问底层操作系统资源,例如文件系统。本文将展示如何在 Rust 和 WebAssembly 中编写高性能 Deno 应用程序。

设置

第一步当然是安装 Deno , 在大多数操作系统中,只需要一行命令

$ curl -fsSL https://deno.land/x/install/install.sh | sh

既然我们要用 Rust 写函数,也需要安装 Rust 语言的编译器与工具.

$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

最后, ssvmup 工具自动执行构建过程并生成所有工件,使 Deno 应用程序可以轻松调用 Rust 函数。同样,需要安装 ssvmup 依赖项。

$ curl https://raw.githubusercontent.com/second-state/ssvmup/master/installer/init.sh -sSf | sh
`

注意:ssvmup 使用 wasm-bindgen 在 JavaScript 和 Rust 源代码之间自动生成“胶水”代码,以便 JavaScript 和 Rust 可以使用各自的本机数据类型进行通信。没有 ssvmup,函数参数和返回值将限于 WebAssembly 本地支持的简单类型(即32位整数)。例如,如果没有 ssvmup 和 wasm-bindgen ,则无法使用字符串或数组。

Hello world

首先,让我们看一下Deno 的 hello world 示例,从 GitHub 获取 hello world 源代码和应用程序模板。

Rust 函数位于 src/ lib.rs 文件中,只需在输入字符串前加上“ hello” 即可。注意, say() 函数使用# [wasm_bindgen] 进行了注释,从而使 ssvmup 可以生成必要的“管道”。基于此,我们可以从 TypeScript 调用 Rust 函数。

#[wasm_bindgen]
pub fn say(s: &str) -> String {
  let r = String::from("hello ");
  return r + s;
}

Deno 应用程序位于 deno / server.ts 文件中。该应用程序从 pkg / functions_lib.js 文件导入 Rust 的 say() 函数,该文件由 ssvmup 工具生成。 functions_lib.js 文件名取决于 Cargo.toml 文件中定义的 Rust 项目名称。

import { serve } from "https://deno.land/std@0.54.0/http/server.ts";
import { say } from '../pkg/functions_lib.js';

type Resp = {
    body: string;
}

const s = serve({ port: 8000 });
console.log("http://localhost:8000/");
for await (const req of s) {
  let r = {} as Resp;
  r.body = say (" World\n");
  req.respond(r);
}

现在,运行 ssvmup 将 Rust 函数构建为 Deno WebAssembly 函数。

$ ssvmup build --target deno

ssvmup 成功完成后,您可以检查 pkg / functions_lib.js 文件,了解如何使用 Deno WebAssembly API 执行已编译的 WebAssembly 文件 pkg / functions_lib.wasm

接下来,运行 Deno 应用程序。 Deno 需要读取文件系统的权限,因为它需要加载 WebAssembly 文件。同时,Deno 也需要访问网络,因为它需要接收和响应 HTTP 请求。

$ deno run --allow-read --allow-net deno/server.ts

现在,在另一个终端窗口中,可以访问 Deno Web 应用程序,通过 HTTP 连接 say hello!

$ curl http://localhost:8000/

hello World

一个复杂的例子

这个入门模板项目包括许多详细的示例,展示了如何在 Deno TypeScript 和 Rust 函数之间传递复杂的数据。这是 src/ lib.rs 中其他的 Rust 函数。请注意,它们都用 #[wasm_bindgen] 注释。

#[wasm_bindgen]
pub fn obfusticate(s: String) -> String {
  (&s).chars().map(|c| {
    match c {
      'A' ..= 'M' | 'a' ..= 'm' => ((c as u8) + 13) as char,
      'N' ..= 'Z' | 'n' ..= 'z' => ((c as u8) - 13) as char,
      _ => c
    }
  }).collect()
}

#[wasm_bindgen]
pub fn lowest_common_denominator(a: i32, b: i32) -> i32 {
  let r = lcm(a, b);
  return r;
}

#[wasm_bindgen]
pub fn sha3_digest(v: Vec<u8>) -> Vec<u8> {
  return Sha3_256::digest(&v).as_slice().to_vec();
}

#[wasm_bindgen]
pub fn keccak_digest(s: &[u8]) -> Vec<u8> {
  return Keccak256::digest(s).as_slice().to_vec();
}

也许最有趣的是 create_line() 函数。这个函数需要两个 JSON 字符串。每个字符串代表一个 Point 结构,并返回一个代表 Line 结构的 JSON 字符串。注意, PointLine 结构都使用 SerializeDeserialize 进行了注释,以便 Rust 编译器自动生成必要的代码来支持它们与 JSON 字符串之间的转换。

use wasm_bindgen::prelude::*;
use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize, Debug)]
struct Point {
  x: f32,
  y: f32
}

#[derive(Serialize, Deserialize, Debug)]
struct Line {
  points: Vec<Point>,
  valid: bool,
  length: f32,
  desc: String
}

#[wasm_bindgen]
pub fn create_line (p1: &str, p2: &str, desc: &str) -> String {
  let point1: Point = serde_json::from_str(p1).unwrap();
  let point2: Point = serde_json::from_str(p2).unwrap();
  let length = ((point1.x - point2.x) * (point1.x - point2.x) + (point1.y - point2.y) * (point1.y - point2.y)).sqrt();

  let valid = if length == 0.0 { false } else { true };
  let line = Line { points: vec![point1, point2], valid: valid, length: length, desc: desc.to_string() };
  return serde_json::to_string(&line).unwrap();
}

#[wasm_bindgen]
pub fn say(s: &str) -> String {
  let r = String::from("hello ");
  return r + s;
}

接下来,让我们检查一下 JavaScript 程序 deno/test.ts ,这显示了如何调用 Rust 函数。 String&str 是 JavaScript 中的简单字符串, i32 是数字,而 Vec <u8>&[8] 是 JavaScript Uint8Array 。 JavaScript 对象需要先通过 JSON.stringify()JSON.parse() 才能传入 Rust 函数或从 Rust 函数返回。

import { say, obfusticate, lowest_common_denominator, sha3_digest, keccak_digest, create_line } from '../pkg/functions_lib.js';

const encoder = new TextEncoder();

console.log( say("SSVM") );
console.log( obfusticate("A quick brown fox jumps over the lazy dog") );
console.log( lowest_common_denominator(123, 2) );
console.log( sha3_digest(encoder.encode("This is an important message")) );
console.log( keccak_digest(encoder.encode("This is an important message")) );

var p1 = {x:1.5, y:3.8};
var p2 = {x:2.5, y:5.8};
var line = JSON.parse(create_line(JSON.stringify(p1), JSON.stringify(p2), "A thin red line"));
console.log( line );

运行 ssvmup 构建 Rust 库之后,在 Deno 运行时中运行 deno/test.ts 会产生以下输出:

$ ssvmup build ``-``-``target deno 
``...`` Building the wasm file and JS shim file ``in`` pkg``/`` ``...`` 
$ deno run ``-``-``allow``-``read deno``/``test``.``ts 
hello SSVM 
N dhvpx oebja sbk whzcf bire gur ynml qbt 
``246
``Uint8Array``(``32``)`` ``[
``87``,`` ``27``,`` ``231``,`` ``209``,`` ``189``,`` ``105``,`` ``251``,`` ``49``,
``...`` ``...
``]
``Uint8Array``(``32``)`` ``[
``126``,`` ``194``,`` ``241``,`` ``200``,`` ``151``,`` ``116``,`` ``227``,
``...`` ``...
``]
``{
   `` points``:`` ``[`` ``{`` x``:`` ``1.5``,`` y``:`` ``3.8`` ``}``,`` ``{`` x``:`` ``2.5``,`` y``:`` ``5.8`` ``}`` ``]``,`` 
   valid``:`` ``true``,`` 
   length``:`` ``2.2360682``,`` 
   desc``:`` ``"A thin red line"
``}`

接下来是什么?

现在,我们可以创建 Rust 函数,并从 Deno TypeScript 应用程序访问 Rust 函数。接下来,我们可以用 Rust 函数编写计算密集型任务,并通过 Deno 提供高性能和安全的 Web 服务。此类服务的示例包括 机器学习图像识别


以上所述就是小编给大家介绍的《如何在 Deno 应用程序中调用 Rust 函数》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Go Web 编程

Go Web 编程

[新加坡]Sau Sheong Chang(郑兆雄) / 黄健宏 / 人民邮电出版社 / 2017-11-22 / 79

《Go Web 编程》原名《Go Web Programming》,原书由新加坡开发者郑兆雄(Sau Sheong Chang)创作、 Manning 出版社出版,人名邮电出版社引进了该书的中文版权,并将其交由黄健宏进行翻译。 《Go Web 编程》一书围绕一个网络论坛 作为例子,教授读者如何使用请求处理器、多路复用器、模板引擎、存储系统等核心组件去构建一个 Go Web 应用,然后在该应用......一起来看看 《Go Web 编程》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换