我想在我的网络应用的每一帧上对大量数据进行计算。 JavaScript只会使用其中的一部分,因此,不是每帧在WebAssembly和JavaScript之间来回发送整套数据,如果数据是在我的WebAssembly模块内部维护的话,那就太好了。
在C中,这样的东西起作用:
#include <emscripten/emscripten.h>
int state = 0;
void EMSCRIPTEN_KEEPALIVE inc() {
state++;
}
int EMSCRIPTEN_KEEPALIVE get() {
return state;
}
Rust可以做同样的事吗?我尝试使用static
这样做:
static mut state: i32 = 0;
pub fn main() {}
#[no_mangle]
pub fn add() {
state += 1;
}
#[no_mangle]
pub fn get() -> i32 {
state
}
但似乎static
变量不可变。
答案 0 :(得分:2)
Francis Gagné is absolutely correct全局变量通常会使您的代码变得更糟,您应该避免使用它们。
但是,对于WebAssembly的特定情况,因为今天,我们不必担心这个问题:
如果您有多个帖子
我们可以选择使用可变的静态变量,如果我们有充分的理由这样做:
// Only valid because we are using this in a WebAssembly
// context without threads.
static mut STATE: i32 = 0;
#[no_mangle]
pub extern fn add() {
unsafe { STATE += 1 };
}
#[no_mangle]
pub extern fn get() -> i32 {
unsafe { STATE }
}
我们可以看到这个NodeJS驱动程序的行为:
const fs = require('fs-extra');
fs.readFile(__dirname + '/target/wasm32-unknown-unknown/release/state.wasm')
.then(bytes => WebAssembly.instantiate(bytes))
.then(({ module, instance }) => {
const { get, add } = instance.exports;
console.log(get());
add();
add();
console.log(get());
});
0
2
答案 1 :(得分:1)
error[E0133]: use of mutable static requires unsafe function or block
通常,访问可变全局变量是 unsafe ,这意味着您只能在unsafe
块中执行此操作。使用可变的全局变量,很容易意外地创建悬空引用(想想对全局可变Vec
项的引用),数据竞争(如果你有多个线程 - Rust没有&t; t小心你没有实际使用线程)或以其他方式调用undefined behavior。
全局变量通常不是问题的最佳解决方案,因为它会降低您的软件灵活性并降低可重用性。相反,请考虑明确地(通过引用,因此您不需要将其复制)传递给需要对其进行操作的函数。这使得调用代码可以使用多个独立状态。
这是分配唯一状态并修改它的示例:
type State = i32;
#[no_mangle]
pub extern fn new() -> *mut State {
Box::into_raw(Box::new(0))
}
#[no_mangle]
pub extern fn free(state: *mut State) {
unsafe { Box::from_raw(state) };
}
#[no_mangle]
pub extern fn add(state: *mut State) {
unsafe { *state += 1 };
}
#[no_mangle]
pub extern fn get(state: *mut State) -> i32 {
unsafe { *state }
}
const fs = require('fs-extra');
fs.readFile(__dirname + '/target/wasm32-unknown-unknown/release/state.wasm')
.then(bytes => WebAssembly.instantiate(bytes))
.then(({ module, instance }) => {
const { new: newFn, free, get, add } = instance.exports;
const state1 = newFn();
const state2 = newFn();
add(state1);
add(state2);
add(state1);
console.log(get(state1));
console.log(get(state2));
free(state1);
free(state2);
});
2
1
注意 - 当前需要在发布模式下编译才能工作。调试模式目前存在一些问题。
不可否认,这并不是 less 不安全,因为你正在传递原始指针,但它使调用代码更清楚地表明存在一些可变状态被操纵。另请注意,现在调用者负责确保正确处理状态指针。