繁体   English   中英

如何直接从原生 JavaScript 前端与 Emscripten Web Worker 交互

[英]How to interact with an Emscripten Web Worker directly from a native JavaScript front

如何从原生 JavaScript 有效地将参数列表发送到 Emscripten Web Worker? 我的数据(参数集)是Float32ArrayUInt16Arrayint等大型数组的不均匀组合。 下面的示例有效,但我不能使用列表、字典或任何其他方式来制作与 int 混合的 TypedArrays 元组. 目前,除非输入是一个单一的 TypedArray,否则它会被转换成几个字节。 例如,以下行将发送三个单字节,每个参数一个字节。

        test_data_worker([b8verts, 150000, b8faces]);  // doesn't work

我的问题实际上是,如何将元组编码为 C 结构体。 我可以使用诸如 struct.js 之类的库,但它们会效率低下(需要转换,并且参数不能转移)。 对于这种情况,Emscripten 有什么解决方案。 请注意,我的特殊要求是我希望我的 JavaScript 直接postMessage()到 Emscripten 编译的 C++ 函数中,而无需通过前端的发送方 C++ 程序或 Worker 端的接收方 JavaScript 代码进行中介。

<html>
<script>
    'use strict';
    var worker = new Worker('./emworker.compiled.js');

    var api_info = {
        test: {
            funcName: "worker_function",
            callbackId: 3,
        },
    };

    function test_data_worker(arguments_data_buffer) {
        // The protocol used by Emscripten
        worker.postMessage( {
                funcName: api_info.test.funcName,
                callbackId: api_info.test.callbackId,
                data: arguments_data_buffer,
                // 'finalResponse': false,
        }
        // , [arguments_data_buffer]  //uncommet for transferable
       );
    }

    function demo_request() {
        var verts = new Float32Array([3.141592651234567890123456780,1,2, 3,4,5, 6,7,8, 9,0.5,1.5]);
        var faces = new Uint16Array([0,1,2, 1,2,3, 0,1,3, 0,2,3]);
        var b8verts=new Uint8Array(verts.buffer);
        var b8faces=new Uint8Array(faces.buffer);

        test_data_worker(b8verts);  // b8verts.buffer to make it transferrable
// Desired:
        //test_data_worker([b8verts, b8faces]);  // Doesnt work. sends two bytes instead
        //test_data_worker([b8verts, 60, b8faces]);  // doesnt work
        //test_data_worker({verts:b8verts, d:60, faces:b8faces});  // doesnt work
    }


    worker.addEventListener('message', function(event) {
        // event.data is {callbackId: -1, finalResponse: true, data: 0}
        switch (event.data.callbackId) {
            case api_info.test.callbackId: //api_revlookup.:
                // console.log("Result sent back from web worker", event.data);
                // Reinterpret data
                var uint8Arr = event.data.data;
                var returned_message = String.fromCharCode.apply(null, uint8Arr)
                console.log(returned_message);
                break;
            default:
                console.error("Unrecognised message sent back.");
        }
    }, false);

    demo_request();
    console.log("request() sent.");
</script>
</html>

和 Worker 的 C++ 代码就像

#include <iostream>
#include <emscripten/emscripten.h>

extern "C" {
    int worker_function(void* data, int size);
}

std::string hexcode(unsigned char byte) {
    const static char codes[] = "0123456789abcdef_";
    std::string result = codes[(byte/16) % 16] + ( codes[byte % 16] + std::string());
    return std::string(result = codes[(byte/16) % 16] + ( codes[byte % 16] + std::string()));
}


int worker_function(void* data, int size) {
    {
    std::cout << "As bytes: ";
    size_t i = 0 ;
    char* char_data = (char*)data;
    for (; i < size; ++i) {
        std::cout << hexcode((char_data)[i]) << " ";
    }
    std::cout << std::endl;
    }

    {
    std::cout << "As float: ";
    float* typed_data = (float*)data;
    size_t typed_size = (size + sizeof(float)-1) / sizeof(float);
    for (size_t i = 0; i < typed_size; ++i) {
        std::cout << typed_data[i] << " ";
    }
    std::cout << std::endl;
    }

    std::string result = std::string("I received ") + std::to_string(size) + " bytes.";
    char* resstr = (char*)result.c_str();
    emscripten_worker_respond(resstr, result.size()); // not needed really
    return 314;  // ignored
}

void worker_function2(float*verts, int numverts, int*faces, int numfaces) {
    //
}

int main(){return 0;}

它以以下方式使用 Emscripten 编译:

em++  -s EXPORTED_FUNCTIONS="['_main', '_worker_function' , '_worker_function2' ]" \
  -s NO_EXIT_RUNTIME=1 \
  -s DEMANGLE_SUPPORT=1 \
  -s BUILD_AS_WORKER=1 -DBUILD_AS_WORKER  \
  -pedantic -std=c++14 \
  emworker.cpp \
  -o ./emworker.compiled.js

我在 Web Worker 上的 API 需要发送和接收多种类型的元组,即它将具有如下输入和输出:

typedef struct vf_pair {
    std::vector<float> verts,  // or a pair<float*,int>
    std::vector<int> faces
} mesh_geometry;
int query_shape(char* reduce_operator, char* shape_spec_json, float* points, int point_count);
struct vf_pair get_latest_shape(int obj_id);
struct vf_pair meshify(char* implicit_object);

您可以在以下 repo 中找到我使用的模式。 它是有效的。 它与 Web Workers 来回交换大型类型数组和原始类型值:

https://github.com/sohale/implisolid/blob/master/js_iteration_2/js/implisolid_worker.js

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM