一、首先要让示例跑起来
运行以下命令,编译一个简单的示例:
em++ tests/worker_api_worker.cpp -s BUILD_AS_WORKER=1 -s EXPORTED_FUNCTIONS="['_one']" -o worker.js
em++ tests/worker_api_main.cpp -o main.html
浏览器打开main.html,应该可以看到结果了。
备注:所有示例的编译方法,可以参见 emscripten\tests\runner.py 文件。
二、emscripten_call_worker的参数
调用worker的方法通过这个emscripten_call_worker函数实现,看看它的参数定义:
/* * Asynchronously call a worker. * * The worker function will be called with two parameters: a * data pointer, and a size. The data block defined by the * pointer and size exists only during the callback and * _cannot_ be relied upon afterwards - if you need to keep some * of that information around, you need to copy it to a safe * location. * * The called worker function can return data, by calling * emscripten_worker_respond(). If called, and if a callback was * given, then the callback will be called with three arguments: * a data pointer, a size, and * an argument that was provided * when calling emscripten_call_worker (to more easily associate * callbacks to calls). The data block defined by the data pointer * and size behave like the data block in the worker function - * it exists only during the callback. * * @funcname the name of the function in the worker. The function * must be a C function (so no C++ name mangling), and * must be exported (EXPORTED_FUNCTIONS). * @data the address of a block of memory to copy over * @size the size of the block of memory * @callback the callback with the response (can be null) * @arg an argument to be passed to the callback */ void emscripten_call_worker(worker_handle worker, const char *funcname, char *data, int size, void (*callback)(char *, int, void*), void *arg);
参数说明:
worker — 句柄
funcname — worker里的函数名称,C风格,并且使用EXPORTED_FUNCTIONS导出
data — 数据地址
size — 数据大小
callback — 回调函数(当异步执行完成时,回调这个函数,同时会把data 和size 返回,但是不要期望此data地址还是传入的data地址)
arg — 回调函数的参数
令人郁闷的地方:
(1)传入的data 和 size,是传值,而不是指针和引用,因为emscripten是将data复制一份,发给worker
(2)callback收到的data,仍然是传值,是数据的拷贝
(3)所以不要期望主程序与worker之间能够共享指针。
三、一点点体会
1、emscripten_create_worker = 在线程池中创建了一个线程
2、emscripten_call_worker = 主程序发送消息给线程(在js中,实际体现在onmessage函数里)
onmessage = function(msg) { //确定消息函数 var func = Module['_' + msg.data['funcName']]; if (!func) throw 'invalid worker function to call: ' + msg.data['funcName']; var data = msg.data['data']; if (data) { //复制传入的参数数据 if (!data.byteLength) data = new Uint8Array(data); if (!buffer || bufferSize < data.length) { if (buffer) _free(buffer); bufferSize = data.length; buffer = _malloc(data.length); } HEAPU8.set(data, buffer); } inWorkerCall = true; workerResponded = false; workerCallbackId = msg.data['callbackId']; if (data) { //调用相应的消息函数 func(buffer, data.length); } else { func(0, 0); } inWorkerCall = false; }
3、emscripten_worker_respond = 线程发送消息给主程序
四、线程交互的麻烦
1、web worker里面无法调用webgl
2、worker里生成图片,再传回主函数
3、线程如何暂停(不是terminate)?线程工作时是不响应onmessage的。
找到一个解决方案:http://msmvps.com/blogs/theproblemsolver/archive/2012/05/02/html5-background-tasks-using-web-workers.aspx
还有一个示例:http://demos.html5support.nl/WebWorkers/Chunked
Using a chunking algorithm
The solution is to use a chunking algorithm. This algorithm brakes the calculation into different groups and use the setTimeout() API to execute the next chunk after a small delay. The result of using setTimeout() is that the message posted can be read and we can actually pause and resume the worker execution. Using a chunking algorithm out background worker JavaScript looks like this:
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/200266.html原文链接:https://javaforall.net
