先在c文件中创建一个用于并发执行的方法:
#ifndef EM_PORT_API
#if defined(__EMSCRIPTEN__)
#include <emscripten.h>
#if defined(__cplusplus)
#define EM_PORT_API(rettype) extern "C" rettype EMSCRIPTEN_KEEPALIVE
#else
#define EM_PORT_API(rettype) rettype EMSCRIPTEN_KEEPALIVE
#endif
#else
#if defined(__cplusplus)
#define EM_PORT_API(rettype) extern "C" rettype
#else
#define EM_PORT_API(rettype) rettype
#endif
#endif
#endif
#include <stdio.h>
double Random()
{
static int seed = 1;
static int const a = 16807, m = 2147483647, q = 127773, r = 2836;
seed = a * (seed % q) - r * (seed / q);
if (seed < 0) seed += m;
return (double)seed / (double)m;
}
EM_PORT_API(double) Pi(int trials)
{
double sum = 0.0;
for (int j = 0; j < 100; j++)
{
int hits = 0;
for (int i = 0; i < trials; i++)
{
double x = Random();
double y = Random();
if (x * x + y * y < 1.0)
hits++;
}
sum += 4.0 * hits / trials;
printf("Worker: Pi() round %d.\n", j + 1);
}
return sum / 100.0f;
}
这里创建了一个计算圆周率的方法Pi()。
在编译之前,额外准备一个pre.js文件(该文件将被插入到 emcc生成的.js文件之前):
Module = {};
Module.onRuntimeInitialized = function() {
postMessage("Worker Ready.");
}
onmessage = function(e){
console.log("Worker: message from mainThread:" + e.data);
console.log("Worker: mission start.");
var p = Module._Pi(e.data);
postMessage(p);
console.log("Worker: mission finished.");
}
pre.js中定义了onmessage()回调函数,用于处理来自主线程的消息。onmessage()函数将根据主线程传来的参数计算圆周率,并将计算结果通过postMessage()方法发送回主线程。另外,即使 在Worker中,Module的编译和初始化仍然是异步的。Worker加载完 pre.js文件并不意味着Module运行时可用,仍然需要采取某种通知机制,确保Worker在开始调用Module前Module已经初始化完成。
这里通过Module.onRuntimeInitialized()回调方法来通知主线程已经准备完毕。
编译pi.cc文件:
emcc code/1209/pi.cc --pre-js code/1209/pre.js -o code/1209/pi.js
其中--pre-js代表编译成为pi.js的前置文件,与之相对的还有--post-js,之表示后置文件。
创建pi.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
var worker = new Worker("./pi.js");
worker.onmessage = function (e) {
console.log("mainThread: message from Worker:" + e.data);
if (e.data == "Worker Ready.") {
worker.postMessage(2000);
}
}
setInterval(function () { console.log("mainThread: timer()"); }, 1000);
</script>
<script src="pi.js"></script>
</body>
</html>
当收到Worker Ready.消息确认Worker中的Module准备完毕后,发送任务参数2000给Worker计算圆周率。
在浏览器运行pi.html后F12显示:
同时任务管理器显示浏览器占用:
由于Worker中执行的运算,CPU核心处于满负荷状态,但主线程并未阻塞,仍然在定时输出
timer日志。