使用 Emscripten C++ Web Worker 高效传输大型数组:哪个 JavaScript 设计更好?

Efficient transfer of large arrays with an Emscripten C++ Web Worker: which JavaScript design is better?

我有一个 Emscripten C++ Web Worker,哪种设计可以更有效地将大数据传输到 JavaScript 程序?

由于web worker 做clone() 和序列化,通过web worker 消息系统传输,这里有一些开销。还需要一些代码将 C++ 端的结果数据从 HEAP32 转换为 JavaScript 数组 ( C -> JS ).

我所说的高效是指哪种设计更快,即哪种设计导致触发更少 newgc()(构造和销毁 JS 对象)。我的 Web Worker 使用了一个用 C++ 编写的核心函数,其中 returns 大数组(两个 float[V][3]int[N][3] 的数组,N=V=10000。它将用于更新 ThreeJS Geometry,在一个网页上会长期被调用数万次,除了速度慢,还可能导致浏览器变慢、卡顿或崩溃。

  1. 用JS写一个Web Worker,导入JS代码用Emscripten编译。 缺点:这个选项似乎不可行,因为web-worker端需要导入编译后的JS文件。 数据交换: C++ -> JS -> message(serialise) -> JS。设计:(C++)JS <-WW-> JS文件: core_mc_algorithm.cpp, worker.js, main.js .
  2. 使用使用-s BUILD_AS_WORKER=1编译的C++ Web Worker,在接收数据的主端写一些其他C++代码,并在主端将结果从HEAP转换为JS:(WebWorker data traser handled by Emscripten):优点:高效传输,但需要两次转换。 风险:在C++方面,它需要从vector到array的多次复制等。数据交换: C++ -> message(serialise) -> C++ -> JS,设计:(C++) <-WW-> C++(JS)文件: worker.cpp, main.cpp, main.js .
  3. 又是一个 C++ Web Worker,但是 Web Worker 函数直接由 JavaScript 中的主程序联系。 优点:conversions/exchanges 没有完成两次。 C++ 和 JS 之间没有单独的交换,这种转换是与 WW 序列化同时完成的。 风险:解码可能比较困难和混乱(协议需要重新实现,本身需要多次转换,效率可能不是很高)。此外,交换实际上可能效率不高,实际上可能不会提高性能。 数据交换: C++ -> message(serialise) -> JS,设计:(C++) <-WW-> JS文件: worker.cpp, main.js .

我有这个 C++ 代码,我想 运行 它作为 Web Worker:

void produce_object (
     REAL* verts_output, int number_of_vertices,
     int* faces_output, int number_of_triangles ) {
    // Run Marching cubes, which produces a vector<int> and a vector<float>.
    // fills in the arrays verts_output[] with coordinates (size: 3*number_of_vertices), 
    // fill in faces_output[] with triangle vertex indices (size: 3*number_of_triangles ), using some numerical code which includes the Marching Cubes algorithm.
}

我需要以下 JavaScript 回调函数才能使用正确的参数进行调用。它在 HTML 文件中定义:

function update_mesh_geometry_callback (verts, faces) {
   /* verts and faces are of type Float32Array and Int32Array of size (3*N) and (3*V). In this function they are used to create the following object, which is added to the scene.*/
   var geo = new THREE.Geometry(verts, faces); // a subclass
   scene.add(new THREE.Mesh(gro, mat, etc));
}

典型尺寸至少:number_of_vertices == 90000 = N,number_of_triangles == 8000 = V。

我相信你是在追求转让。 Worker 在 postMessage 方法中有一个额外的参数: https://developer.mozilla.org/en-US/docs/Web/API/Worker/postMessage

Transferables 仅适用于 ArrayBuffers,它们还从消息传递线程中取消设置缓冲区,您必须牢记这一点,但对于您的情况,这似乎是一个完美的选择,因为它将避免完全复制。

这里有一个玩具代码示例,用于说明您的 worker 中的内容

var vertices = new Float32Array(100000);
var faceIndices = new Uint32Array(50000);
postMessage({vertices: vertices, faceIndices: faceIndices}, [vertices.buffer, faceIndices.buffer]);

您可以在此处阅读有关可转让资产的更多信息: Using transferable objects from a Web Worker