使用 WebAssembly 和 Web Workers 在浏览器中以毫秒为单位执行数百万条 SQL 语句。
使用 WebAssembly 和 Web Workers 在浏览器中以毫秒为单位执行数百万条 SQL 语句。
这是一个相当长的标题,但希望它能引起你的注意!
我一直着迷于在浏览器中,HTML 和 JavaScript 能实现什么。浏览器供应商在 JavaScript 性能方面所做的惊人工作是不可思议的。随着 Chrome V8、微软 Chakra、Mozilla SpiderMonkey 和苹果 JavaScriptCore 的每一次迭代,JavaScript 性能都缩小了与原生代码执行的差距。
web assembly(【http://webassembly.org/】T4)是最新的创新,让我们离在浏览器中执行真正的本地代码又近了一步。我想看看我们已经走了多远,所以我拼凑了一个测试真实代码库的例子,在这个例子中,是 Sqlite 数据库—http://sqlite.org/。在我的测试中,我使用了这里找到的 Emscripten 编译版 SQLite—https://github.com/kripken/sql.js/。
我的测试使用的是最新版本的 Chrome Canary,下面的标志设置为 enabled:
chrome://flags/#enable-webassembly
我的测试机器是一台戴尔 XPS 台式机,配备:
Processor Intel(R) Core(TM) i7–4770 CPU @ 3.40GHz, 3401 Mhz, 4 Core(s), 8 Logical Processor(s)24 Gigs of RAM
256 SSD Drive
我创建了 2 个文件,主要的 index.html
<html>
<head>
<title>WebAssembly Test</title>
<script>var aListeners = [];
var results=[];
var times=[];
var workers=[];
//load up our workers
for(var i=0;i<8;i++){
workers[i]=new Worker("worker.js");
workers[i].onmessage = function (oEvent) {
if (aListeners[oEvent.data.id]) { aListeners[oEvent.data.id](oEvent.data.evaluated,this); }
delete aListeners[oEvent.data.id];
};
}function getRandomWorker(arr) {
return arr[Math.floor(Math.random()*arr.length)];
}
var asyncEval = (function () {
return function (worker, sCode, fListener) {
aListeners.push(fListener || null);
worker.postMessage({
"id": aListeners.length - 1,
"code": sCode
});
};})();//Our test function
function test(numReq,code) {
console.time("Total_Elapsed");
times=[];
results=[];
times.push((new Date()).valueOf());
var num=numReq || 10000;
for(var i=0;i<num;i++) {
asyncEval(getRandomWorker(workers),code || "Date()", function (result,worker) {
times.push((new Date()).valueOf());
results.push(result);
if(results.length==num) {
console.timeEnd("Total_Elapsed");
console.log("Processing Time for all workers: "+(parseInt(times[times.length-1])-parseInt(times[0])).toString()+"ms");
var numRequests=results.length*parseInt(results[0].split(": ")[1]);
console.log("Total sql statements processed: "+numRequests);
}
});
};
return "Executing test ...";
}
</script>
</head>
<body>
Press F12 to view console
</body>
</html>
和 Web Worker 脚本 worker.js
importScripts("sql.js");//Init sqlite database
var db = new SQL.Database();//Our test function
var run_sql=function(numReq,sql) {
var n=numReq || 10000;
var results=[];
var elapsed=0;
var stmt = db.prepare(sql || "select datetime() as dt;");
var start = (new Date()).getTime();
for(var i=0;i<n;i++) {
var rows = stmt.getAsObject({});
results.push(rows);
if(results.length==n) {
var end = (new Date()).getTime();
elapsed="Elapsed sql statement:"+(end-start).toString()+" ms #Rows: "+results.length.toString();
}
}
stmt.free();
return elapsed;
}//Run code to init JIT compilation
run_sql();//Message Handler
onmessage = function (oEvent) {
postMessage({
"id": oEvent.data.id,
"evaluated": process(oEvent.data.code)
});
}function process(code) {
var result=null;
try {
result=eval(code);
}
catch(e)
{
result = "Error: "+e.message;
}
return result;
}
要运行测试,您需要在一个 web 服务器上托管三个文件, 、worker.js 和 sql.js 。我在我的 Window 的机器上使用 IIS,但是任何操作系统上的任何静态 web 服务器都可以。
当您第一次加载 index.html 时,您会得到一条简单的消息,告诉您在浏览器中访问开发工具。在我的机器上,它看起来像这样

你会注意到的第一件事是 Chrome 的工作人员负责将 sql.js 转换成 WebAssembly。所有这些如何工作的细节超出了本文的范围,但是您可以在这里找到更多信息:
https://github.com/kripken/sql.js
还有这里
[## 开发者指南- WebAssembly
为了编译成 WebAssembly,我们现在需要从源代码编译 LLVM。需要以下工具作为…
webassembly.org](http://webassembly.org/getting-started/developers-guide/)
为了运行我们的第一个测试,我们在开发人员控制台中键入以下内容:
test(1,"run_sql(1000,'select datetime() as dt;')")
这将执行 SQL 语句‘select datetime()as dt;’ 在一个 Web Worker 内循环 1000 次。我的机器上的结果如下:

所以我们在 8.29 毫秒内处理了 1000 个 SQL 请求。
让我们在一个 web worker 中尝试 10,000 个 SQL 请求:

因此,我们在 67 毫秒内处理了 10,000 个 SQL 请求。因为我的机器上有 8 个内核,所以我配置了 8 个 web worker,所以让我们在这些 web worker 之间再次运行测试:

因此,使用 web workers,我们可以在大约一半的时间内处理 10,000 个 SQL 请求。
100,000 个 SQL 请求怎么样:

不算太坏,100,000 个 SQL 请求用了大约 211 毫秒。
文章的标题谈到在几秒钟内处理数百万个 SQL 请求,所以让我们对 1,000,000 个 SQL 请求进行测试:

在我的机器上,需要
~ 2 秒钟运行一百万条 SQL select 语句!
数据库插入怎么样?以下代码将一百万条记录插入 SQL 表中:

所以…
在一个表中插入一百万行大约需要 2.2 秒
这真是令人印象深刻,而 WebAssembly 才刚刚起步。
显然,这些测试非常简单,根据您的 SQL 应用程序的性质,您的结果可能会有所不同。然而,它确实说明了我们在浏览器中的原始 JavaScript 性能方面取得了多大的进步。
我很想听到你的反馈,所以请向你的关注者推荐这篇文章:-)



