使用 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
).
我所说的高效是指哪种设计更快,即哪种设计导致触发更少 new
和 gc()
(构造和销毁 JS 对象)。我的 Web Worker 使用了一个用 C++ 编写的核心函数,其中 returns 大数组(两个 float[V][3]
和 int[N][3]
的数组,N=V=10000。它将用于更新 ThreeJS Geometry,在一个网页上会长期被调用数万次,除了速度慢,还可能导致浏览器变慢、卡顿或崩溃。
- 用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 .
- 使用使用
-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 .
- 又是一个 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 仅适用于 ArrayBuffer
s,它们还从消息传递线程中取消设置缓冲区,您必须牢记这一点,但对于您的情况,这似乎是一个完美的选择,因为它将避免完全复制。
这里有一个玩具代码示例,用于说明您的 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
我有一个 Emscripten C++ Web Worker,哪种设计可以更有效地将大数据传输到 JavaScript 程序?
由于web worker 做clone()
和序列化,通过web worker 消息系统传输,这里有一些开销。还需要一些代码将 C++ 端的结果数据从 HEAP32 转换为 JavaScript 数组 ( C -> JS
).
我所说的高效是指哪种设计更快,即哪种设计导致触发更少 new
和 gc()
(构造和销毁 JS 对象)。我的 Web Worker 使用了一个用 C++ 编写的核心函数,其中 returns 大数组(两个 float[V][3]
和 int[N][3]
的数组,N=V=10000。它将用于更新 ThreeJS Geometry,在一个网页上会长期被调用数万次,除了速度慢,还可能导致浏览器变慢、卡顿或崩溃。
- 用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 . - 使用使用
-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 . - 又是一个 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 仅适用于 ArrayBuffer
s,它们还从消息传递线程中取消设置缓冲区,您必须牢记这一点,但对于您的情况,这似乎是一个完美的选择,因为它将避免完全复制。
这里有一个玩具代码示例,用于说明您的 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