我想对网络应用程序的每一帧的大量数据进行计算。JavaScript 只会使用其中的一个子集,因此与其在 WebAssembly 和 JavaScript 之间来回发送每一帧的整个数据集,不如在我的 WebAssembly 模块内部维护数据。
在 C 中,类似这样的工作:
#include <emscripten/emscripten.h>
int state = 0;
void EMSCRIPTEN_KEEPALIVE inc() {
state++;
}
int EMSCRIPTEN_KEEPALIVE get() {
return state;
}
Run Code Online (Sandbox Code Playgroud)
在 Rust 中可以做同样的事情吗?我尝试这样做static:
static mut state: i32 = 0;
pub fn main() {}
#[no_mangle]
pub fn add() {
state += 1;
}
#[no_mangle]
pub fn get() -> i32 {
state
}
Run Code Online (Sandbox Code Playgroud)
但似乎static变量不能是可变的。
Francis Gagné 是绝对正确的,全局变量通常会使您的代码变得更糟,您应该避免使用它们。
但是,对于今天的 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 }
}
Run Code Online (Sandbox Code Playgroud)
我们可以看到这个 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());
});
Run Code Online (Sandbox Code Playgroud)
// 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 }
}
Run Code Online (Sandbox Code Playgroud)
\n\n\nRun Code Online (Sandbox Code Playgroud)\nerror[E0133]: use of mutable static requires unsafe function or block\n
一般来说,访问可变全局变量是不安全的,这意味着您只能在unsafe块中执行此操作。使用可变的全局变量,很容易意外地创建悬空引用(想象一下对全局可变的项的引用Vec)、数据争用(如果你有多个线程——Rust 不在乎你是否不这样做)实际上使用线程)或以其他方式调用未定义的行为。
全局变量通常不是问题的最佳解决方案,因为它会降低软件的灵活性和可重用性。相反,请考虑将状态显式传递(通过引用,因此您不需要复制它)到需要对其进行操作的函数。这使得调用代码可以处理多个独立状态。
\n\n这是分配唯一状态并修改它的示例:
\n\ntype State = i32;\n\n#[no_mangle]\npub extern fn new() -> *mut State {\n Box::into_raw(Box::new(0))\n}\n\n#[no_mangle]\npub extern fn free(state: *mut State) {\n unsafe { Box::from_raw(state) };\n}\n\n#[no_mangle]\npub extern fn add(state: *mut State) {\n unsafe { *state += 1 };\n}\n\n#[no_mangle]\npub extern fn get(state: *mut State) -> i32 {\n unsafe { *state }\n}\nRun Code Online (Sandbox Code Playgroud)\n\nconst fs = require(\'fs-extra\');\n\nfs.readFile(__dirname + \'/target/wasm32-unknown-unknown/release/state.wasm\')\n .then(bytes => WebAssembly.instantiate(bytes))\n .then(({ module, instance }) => {\n const { new: newFn, free, get, add } = instance.exports;\n\n const state1 = newFn();\n const state2 = newFn();\n\n add(state1);\n add(state2);\n add(state1);\n\n console.log(get(state1));\n console.log(get(state2));\n\n free(state1);\n free(state2);\n});\nRun Code Online (Sandbox Code Playgroud)\n\nerror[E0133]: use of mutable static requires unsafe function or block\nRun Code Online (Sandbox Code Playgroud)\n\n注意\xe2\x80\x94 目前需要在发布模式下编译才能工作。调试模式目前存在一些问题。
\n\n诚然,这并不是不安全,因为您正在传递原始指针,但它使调用代码中更清楚地表明存在一些正在操纵的可变状态。另请注意,现在调用者有责任确保正确处理状态指针。
\n| 归档时间: |
|
| 查看次数: |
1384 次 |
| 最近记录: |