>

前端高性能计算之二,前端高性能计算之一

- 编辑:至尊游戏网站 -

前端高性能计算之二,前端高性能计算之一

前端高品质计算之风姿罗曼蒂克:WebWorkers

2017/10/21 · HTML5 · WebWorkers

原作出处: magicly   

前段时间做二个等级次序,里面涉及到在前端做大批量乘除,直接用js跑了须臾间,大致必要15s的时光, 也正是顾客的浏览器会卡死15s,那几个完全选取不了。

即便有V8那样牛逼的斯特林发动机,但大家驾驭js并不适合做CPU密集型的推断,龙精虎猛是因为单线程,二是因为动态语言。我们就从那三个突破口出手,首先消除“单线程”的范围,尝试用WebWorkers来加快总计。

后边贰个高质量计算之二:asm.js & webassembly

2017/10/21 · HTML5 · webassembly

原稿出处: magicly   

前一篇我们说了要消除高品质总结的四个章程,三个是并发用WebWorkers,另二个便是用更底层的静态语言。

二零一二年,Mozilla的程序猿Alon Zakai在研究LLVM编写翻译器时突发奇想:能或不能把C/C++编写翻译成Javascript,何况尽量达到Native代码的快慢吗?于是她付出了Emscripten编写翻译器,用于将C/C++代码编写翻译成Javascript的一个子集asm.js,质量大致是原生代码的一半。我们能够看看这个PPT。

之后Google开发了Portable Native Client,也是如日中天种能让浏览器运维C/C++代码的本领。 后来打量我们都以为各搞各的非常呀,居然Google, Microsoft, Mozilla, Apple等几家大公司一齐同盟开垦了三个面向Web的通用二进制和文本格式的体系,那就是WebAssembly,官互联网的介绍是:

WebAssembly or wasm is a new portable, size- and load-time-efficient format suitable for compilation to the web.

WebAssembly is currently being designed as an open standard by a W3C Community Group that includes representatives from all major browsers.

所以,WebAssembly有道是是一个前景很好的花色。大家得以看一下眼前浏览器的帮忙情状: 图片 1

什么是WebWorkers

简单说,WebWorkers是贰个HTML5的新API,web开垦者能够透过此API在后台运维一个剧本而不阻塞UI,能够用来做需求多量计量的事情,丰硕利用CPU多核。

世家能够看看那篇小说介绍https://www.html5rocks.com/en/tutorials/workers/basics/, 或者对应的汉语版。

The Web Workers specification defines an API for spawning background scripts in your web application. Web Workers allow you to do things like fire up long-running scripts to handle computationally intensive tasks, but without blocking the UI or other scripts to handle user interactions.

可以张开那几个链接和谐经验一下WebWorkers的增长速度效果。

近期浏览器基本都支持WebWorkers了。 图片 2

安装Emscripten

访问

  1. 下载对应平台版本的SDK

  2. 经过emsdk获取最新版工具

JavaScript

# Fetch the latest registry of available tools. ./emsdk update # Download and install the latest SDK tools. ./emsdk install latest # Make the "latest" SDK "active" for the current user. (writes ~/.emscripten file) ./emsdk activate latest # Activate PATH and other environment variables in the current terminal source ./emsdk_env.sh

1
2
3
4
5
6
7
8
9
10
11
# Fetch the latest registry of available tools.
./emsdk update
 
# Download and install the latest SDK tools.
./emsdk install latest
 
# Make the "latest" SDK "active" for the current user. (writes ~/.emscripten file)
./emsdk activate latest
 
# Activate PATH and other environment variables in the current terminal
source ./emsdk_env.sh
  1. 将下列增加到情状变量PATH中

JavaScript

~/emsdk-portable ~/emsdk-portable/clang/fastcomp/build_incoming_64/bin ~/emsdk-portable/emscripten/incoming

1
2
3
~/emsdk-portable
~/emsdk-portable/clang/fastcomp/build_incoming_64/bin
~/emsdk-portable/emscripten/incoming
  1. 其他

自作者在推行的时候境遇报错说LLVM本子不对,后来参见文档配置了LLVM_ROOT变量就好了,若是你未曾超越难点,能够忽视。

JavaScript

LLVM_ROOT = os.path.expanduser(os.getenv('LLVM', '/home/ubuntu/a-path/emscripten-fastcomp/build/bin'))

1
LLVM_ROOT = os.path.expanduser(os.getenv('LLVM', '/home/ubuntu/a-path/emscripten-fastcomp/build/bin'))
  1. 证明是不是安装好

执行emcc -v,要是设置好会现出如下音讯:

JavaScript

emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 1.37.21 clang version 4.0.0 ( 974b55fd84ca447c4297fc3b00cefb6394571d18) ( 9e4ee9a67c3b67239bd1438e31263e2e86653db5) (emscripten 1.37.21 : 1.37.21) Target: x86_64-apple-darwin15.5.0 Thread model: posix InstalledDir: /Users/magicly/emsdk-portable/clang/fastcomp/build_incoming_64/bin INFO:root:(Emscripten: Running sanity checks)

1
2
3
4
5
6
emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 1.37.21
clang version 4.0.0 (https://github.com/kripken/emscripten-fastcomp-clang.git 974b55fd84ca447c4297fc3b00cefb6394571d18) (https://github.com/kripken/emscripten-fastcomp.git 9e4ee9a67c3b67239bd1438e31263e2e86653db5) (emscripten 1.37.21 : 1.37.21)
Target: x86_64-apple-darwin15.5.0
Thread model: posix
InstalledDir: /Users/magicly/emsdk-portable/clang/fastcomp/build_incoming_64/bin
INFO:root:(Emscripten: Running sanity checks)

Parallel.js

直白采纳WebWorkers接口照旧太繁缛,幸好有人民代表大会器晚成度对此作了包装:Parallel.js。

注意Parallel.js能够通过node安装:

$ npm install paralleljs

1
$ npm install paralleljs

唯独那一个是在node.js下用的,用的node的cluster模块。固然要在浏览器里使用以来, 要求一向利用js:

<script src="parallel.js"></script>

1
<script src="parallel.js"></script>

下一场能够赢得一个全局变量,ParallelParallel提供了mapreduce两个函数式编制程序的接口,能够拾贰分有助于的张开并发操作。

咱俩先来定义一下我们的主题材料,由于业务比较复杂,笔者这里把标题简化成求1-1,0000,0000的和,然后在逐龙精虎猛减去1-1,0000,0000,答案明显: 0! 那样做是因为数字太大的话会有多少精度的难题,两种方法的结果会有局地间隔,会令人以为互相的艺术离谱赖。此主题素材在本身的mac pro chrome61下直接省略地跑js运营的话差十分的少是1.5s(大家其实工作难点供给15s,这里为了防止顾客测验的时候把浏览器搞死,大家简化了难题)。

const N = 一千00000;// 总次数1亿 function sum(start, end) { let total = 0; for (let i = start; i<=end; i += 1) total += i; for (let i = start; i<=end; i += 1) total -= i; return total; } function paraSum(N) { const N1 = N / 10;//我们分成10分,没分分别交付三个web worker,parallel.js会依照计算机的CPU核数营造适当的workers let p = new Parallel([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) .require(sum); return p.map(n => sum((n - 1) * 10000000 + 1, n * 10000000))// 在parallel.js里面没办法直接采纳外界变量N1 .reduce(data => { const acc = data[0]; const e = data[1]; return acc + e; }); }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const N = 100000000;// 总次数1亿
 
function sum(start, end) {
  let total = 0;
  for (let i = start; i<=end; i += 1) total += i;
  for (let i = start; i<=end; i += 1) total -= i;
  return total;
}
 
function paraSum(N) {
  const N1 = N / 10;//我们分成10分,没分分别交给一个web worker,parallel.js会根据电脑的CPU核数建立适量的workers
  let p = new Parallel([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
    .require(sum);
  return p.map(n => sum((n - 1) * 10000000 + 1, n * 10000000))// 在parallel.js里面没法直接应用外部变量N1
    .reduce(data => {
      const acc = data[0];
      const e = data[1];
      return acc + e;
    });
}

代码比较轻便,作者这边说多少个刚用的时候遭遇的坑。

  • require全数必要的函数

譬如说在上诉代码中用到了sum,你需求超前require(sum),要是sum中由用到了另叁个函数f,你还亟需require(f),同样假设f中用到了g,则还索要require(g),直到你require了具备应用的概念的函数。。。。

  • 没法require变量

我们上诉代码作者当然定义了N1,然而无法用

  • ES6编译成ES5日后的题目以至Chrome没报错

实际项目中一齐头大家用到了ES6的特性:数组解构。本来那是异常粗略的特性,以往大部分浏览器都曾经支撑了,可是我那时候配备的babel会编写翻译成ES5,所以会调换代码_slicedToArray,大家能够在线上Babel测试,然后Chrome上面始终不work,也远非此外报错音讯,查了非常久,后来在Firefox下开采,有报错音讯:

ReferenceError: _slicedToArray is not defined

1
ReferenceError: _slicedToArray is not defined

看来Chrome亦非万能的啊。。。

世家能够在此Demo页面测量检验, 提速差非常少在4倍左右,当然照旧得看本身ComputerCPU的核数。 此外笔者后来在同样的微管理器上Firefox55.0.3(陆17个人)测量检验,上诉代码居然只要190ms!!!在Safari9.1.1下也是190ms左右。。。

Hello, WebAssembly!

开创二个文本hello.c

JavaScript

#include <stdio.h> int main() { printf("Hello, WebAssembly!n"); return 0; }

1
2
3
4
5
#include <stdio.h>
int main() {
  printf("Hello, WebAssembly!n");
  return 0;
}

编译C/C++代码:

JavaScript

emcc hello.c

1
emcc hello.c

上述命令会变动四个a.out.js文本,我们得以一贯用Node.js执行:

JavaScript

node a.out.js

1
node a.out.js

输出

JavaScript

Hello, WebAssembly!

1
Hello, WebAssembly!

为了让代码运营在网页里面,推行上边发号出令会变动hello.htmlhello.js三个文件,个中hello.jsa.out.js内容是完全同样的。

emcc hello.c -o hello.html<code>

1
2
emcc hello.c -o hello.html<code>
 

JavaScript

➜ webasm-study md5 a.out.js MD5 (a.out.js) = d7397f44f817526a4d0f94bc85e46429 ➜ webasm-study md5 hello.js MD5 (hello.js) = d7397f44f817526a4d0f94bc85e46429

1
2
3
4
➜  webasm-study md5 a.out.js
MD5 (a.out.js) = d7397f44f817526a4d0f94bc85e46429
➜  webasm-study md5 hello.js
MD5 (hello.js) = d7397f44f817526a4d0f94bc85e46429

接下来在浏览器展开hello.html,能够看出页面 图片 3

方今生成的代码都以asm.js,毕竟Emscripten是每户小编Alon Zakai最初用来扭转asm.js的,暗许输出asm.js也就相差为奇了。当然,能够通过option生成wasm,会变卦多个公文:hello-wasm.html, hello-wasm.js, hello-wasm.wasm

JavaScript

emcc hello.c -s WASM=1 -o hello-wasm.html

1
emcc hello.c -s WASM=1 -o hello-wasm.html

接下来浏览器张开hello-wasm.html,发掘报错TypeError: Failed to fetch。原因是wasm文本是由此XHR异步加载的,用file:////做客会报错,所以大家须要启二个服务器。

JavaScript

npm install -g serve serve

1
2
npm install -g serve
serve

接下来访谈http://localhost:5000/hello-wasm.html,就足以见见正常结果了。

Refers

  • https://developer.mozilla.org/zh-CN/docs/Web/API/Web*Workers*API/Using*web*workers
  • 1 赞 1 收藏 评论

图片 4

调用C/C++函数

前面的Hello, WebAssembly!都是main函数直接打出来的,而我们使用WebAssembly的指标是为了高性能计算,做法多半是用C/C++达成有个别函数实行耗时的总括,然后编译成wasm,暴露给js去调用。

在文件add.c中写如下代码:

JavaScript

#include <stdio.h> int add(int a, int b) { return a + b; } int main() { printf("a + b: %d", add(1, 2)); return 0; }

1
2
3
4
5
6
7
8
9
#include <stdio.h>
int add(int a, int b) {
  return a + b;
}
 
int main() {
  printf("a + b: %d", add(1, 2));
  return 0;
}

有二种方式能够把add格局暴暴露来给js调用。

由此命令行参数暴光API

JavaScript

emcc -s EXPORTED_FUNCTIONS="['_add']" add.c -o add.js

1
emcc -s EXPORTED_FUNCTIONS="['_add']" add.c -o add.js

专一方法名add前必得加_。 然后我们得以在Node.js其间这么使用:

JavaScript

// file node-add.js const add_module = require('./add.js'); console.log(add_module.ccall('add', 'number', ['number', 'number'], [2, 3]));

1
2
3
// file node-add.js
const add_module = require('./add.js');
console.log(add_module.ccall('add', 'number', ['number', 'number'], [2, 3]));

执行node node-add.js会输出5。 要是急需在web页面使用的话,施行:

JavaScript

emcc -s EXPORTED_FUNCTIONS="['_add']" add.c -o add.html

1
emcc -s EXPORTED_FUNCTIONS="['_add']" add.c -o add.html

然后在改换的add.html中步入如下代码:

JavaScript

<button onclick="nativeAdd()">click</button> <script type='text/javascript'> function nativeAdd() { const result = Module.ccall('add', 'number', ['number', 'number'], [2, 3]); alert(result); } </script>

1
2
3
4
5
6
7
  <button onclick="nativeAdd()">click</button>
  <script type='text/javascript'>
    function nativeAdd() {
      const result = Module.ccall('add', 'number', ['number', 'number'], [2, 3]);
      alert(result);
    }
  </script>

下一场点击button,就能够看来实行结果了。

Module.ccall会向来调用C/C++代码的措施,更通用的处境是大家取获得贰个包装过的函数,能够在js里面每每调用,那要求用Module.cwrap,具体细节能够参谋文档。

JavaScript

const cAdd = add_module.cwrap('add', 'number', ['number', 'number']); console.log(cAdd(2, 3)); console.log(cAdd(2, 4));

1
2
3
const cAdd = add_module.cwrap('add', 'number', ['number', 'number']);
console.log(cAdd(2, 3));
console.log(cAdd(2, 4));

概念函数的时候加多EMSCRIPTEN_KEEPALIVE

拉长文件add2.c

JavaScript

#include <stdio.h> #include <emscripten.h> int EMSCRIPTEN_KEEPALIVE add(int a, int b) { return a + b; } int main() { printf("a + b: %d", add(1, 2)); return 0; }

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
#include <emscripten.h>
 
int EMSCRIPTEN_KEEPALIVE add(int a, int b) {
  return a + b;
}
 
int main() {
  printf("a + b: %d", add(1, 2));
  return 0;
}

推行命令:

JavaScript

emcc add2.c -o add2.html

1
emcc add2.c -o add2.html

同样在add2.html中增加代码:

JavaScript

<button onclick="nativeAdd()">click</button> <script type='text/javascript'> function nativeAdd() { const result = Module.ccall('add', 'number', ['number', 'number'], [2, 3]); alert(result); } </script>

1
2
3
4
5
6
7
  <button onclick="nativeAdd()">click</button>
  <script type='text/javascript'>
    function nativeAdd() {
      const result = Module.ccall('add', 'number', ['number', 'number'], [2, 3]);
      alert(result);
    }
  </script>

然而,当您点击button的时候,报错:

JavaScript

Assertion failed: the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)

1
Assertion failed: the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)

能够经过在main()中添加emscripten_exit_with_live_runtime()解决:

JavaScript

#include <stdio.h> #include <emscripten.h> int EMSCRIPTEN_KEEPALIVE add(int a, int b) { return a + b; } int main() { printf("a + b: %d", add(1, 2)); emscripten_exit_with_live_runtime(); return 0; }

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
#include <emscripten.h>
 
int EMSCRIPTEN_KEEPALIVE add(int a, int b) {
  return a + b;
}
 
int main() {
  printf("a + b: %d", add(1, 2));
  emscripten_exit_with_live_runtime();
  return 0;
}

要么也足以一贯在命令行中增添-s NO_EXIT_RUNTIME=1来解决,

JavaScript

emcc add2.c -o add2.js -s NO_EXIT_RUNTIME=1

1
emcc add2.c -o add2.js -s NO_EXIT_RUNTIME=1

只是会报多少个告诫:

JavaScript

exit(0) implicitly called by end of main(), but noExitRuntime, so not exiting the runtime (you can use emscripten_force_exit, if you want to force a true shutdown)exit(0) implicitly called by end of main(), but noExitRuntime, so not exiting the runtime (you can use emscripten_force_exit, if you want to force a true shutdown)

1
exit(0) implicitly called by end of main(), but noExitRuntime, so not exiting the runtime (you can use emscripten_force_exit, if you want to force a true shutdown)exit(0) implicitly called by end of main(), but noExitRuntime, so not exiting the runtime (you can use emscripten_force_exit, if you want to force a true shutdown)

之所以建议使用第豆蔻梢头种方法。

上述变化的代码都以asm.js,只要求在编写翻译参数中增多-s WASM=1中就足以生成wasm,然后利用办法都同样。

用asm.js和WebAssembly实践耗费时间总括

日前图谋职业都做完了, 未来大家来试一下用C代码来优化前一篇中提过的难点。代码相当粗略:

JavaScript

// file sum.c #include <stdio.h> // #include <emscripten.h> long sum(long start, long end) { long total = 0; for (long i = start; i <= end; i += 3) { total += i; } for (long i = start; i <= end; i += 3) { total -= i; } return total; } int main() { printf("sum(0, 1000000000): %ld", sum(0, 1000000000)); // emscripten_exit_with_live_runtime(); return 0; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// file sum.c
#include <stdio.h>
// #include <emscripten.h>
 
long sum(long start, long end) {
  long total = 0;
  for (long i = start; i <= end; i += 3) {
    total += i;
  }
  for (long i = start; i <= end; i += 3) {
    total -= i;
  }
  return total;
}
 
int main() {
  printf("sum(0, 1000000000): %ld", sum(0, 1000000000));
  // emscripten_exit_with_live_runtime();
  return 0;
}

注意用gcc编写翻译的时候供给把跟emscriten连锁的两行代码注释掉,不然编写翻译可是。 大家先直接用gcc编译成native code看看代码运转多块吧?

JavaScript

➜ webasm-study gcc sum.c ➜ webasm-study time ./a.out sum(0, 1000000000): 0./a.out 5.70s user 0.02s system 99% cpu 5.746 total ➜ webasm-study gcc -O1 sum.c ➜ webasm-study time ./a.out sum(0, 1000000000): 0./a.out 0.00s user 0.00s system 64% cpu 0.003 total ➜ webasm-study gcc -O2 sum.c ➜ webasm-study time ./a.out sum(0, 1000000000): 0./a.out 0.00s user 0.00s system 64% cpu 0.003 total

1
2
3
4
5
6
7
8
9
➜  webasm-study gcc sum.c
➜  webasm-study time ./a.out
sum(0, 1000000000): 0./a.out  5.70s user 0.02s system 99% cpu 5.746 total
➜  webasm-study gcc -O1 sum.c
➜  webasm-study time ./a.out
sum(0, 1000000000): 0./a.out  0.00s user 0.00s system 64% cpu 0.003 total
➜  webasm-study gcc -O2 sum.c
➜  webasm-study time ./a.out
sum(0, 1000000000): 0./a.out  0.00s user 0.00s system 64% cpu 0.003 total

可以见见有未有优化差异依旧异常的大的,优化过的代码施行时间是3ms!。really?留神揣摩,笔者for循环了10亿次啊,每一趟for实践差不离是四回加法,五回赋值,二遍比较,而作者生气勃勃共做了三次for循环,也便是说最少是100亿次操作,而自己的mac pro是2.5 GHz Intel Core i7,所以1s应有也就施行25亿次CPU指令操作吧,怎么大概逆天到这种程度,确定是哪个地方错了。想起此前见到的意气风发篇rust测量检验品质的篇章,说rust直接在编写翻译的时候算出了答案, 然后把结果平素写到了编写翻译出来的代码里, 不精晓gcc是或不是也做了类似的业务。在天涯论坛上GCC中-O1 -O2 -O3 优化的法规是怎么样?那篇小说里, 还真有loop-invariant code motion(LICM)针对for的优化,所以本身把代码增添了有的if推断,希望能“糊弄”得了gcc的优化。

JavaScript

#include <stdio.h> // #include <emscripten.h> // long EMSCRIPTEN_KEEPALIVE sum(long start, long end) { long sum(long start, long end) { long total = 0; for (long i = start; i <= end; i += 1) { if (i % 2 == 0 || i % 3 == 1) { total += i; } else if (i % 5 == 0 || i % 7 == 1) { total += i / 2; } } for (long i = start; i <= end; i += 1) { if (i % 2 == 0 || i % 3 == 1) { total -= i; } else if (i % 5 == 0 || i % 7 == 1) { total -= i / 2; } } return total; } int main() { printf("sum(0, 1000000000): %ld", sum(0, 100000000)); // emscripten_exit_with_live_runtime(); return 0; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <stdio.h>
// #include <emscripten.h>
 
// long EMSCRIPTEN_KEEPALIVE sum(long start, long end) {
long sum(long start, long end) {
  long total = 0;
  for (long i = start; i <= end; i += 1) {
    if (i % 2 == 0 || i % 3 == 1) {
      total += i;
    } else if (i % 5 == 0 || i % 7 == 1) {
      total += i / 2;
    }
  }
  for (long i = start; i <= end; i += 1) {
    if (i % 2 == 0 || i % 3 == 1) {
      total -= i;
    } else if (i % 5 == 0 || i % 7 == 1) {
      total -= i / 2;
    }
  }
  return total;
}
 
int main() {
  printf("sum(0, 1000000000): %ld", sum(0, 100000000));
  // emscripten_exit_with_live_runtime();
  return 0;
}

进行结果大致要健康一些了。

JavaScript

➜ webasm-study gcc -O2 sum.c ➜ webasm-study time ./a.out sum(0, 1000000000): 0./a.out 0.32s user 0.00s system 99% cpu 0.324 total

1
2
3
➜  webasm-study gcc -O2 sum.c
➜  webasm-study time ./a.out
sum(0, 1000000000): 0./a.out  0.32s user 0.00s system 99% cpu 0.324 total

ok,大家来编写翻译成asm.js了。

JavaScript

#include <stdio.h> #include <emscripten.h> long EMSCRIPTEN_KEEPALIVE sum(long start, long end) { // long sum(long start, long end) { long total = 0; for (long i = start; i <= end; i += 1) { if (i % 2 == 0 || i % 3 == 1) { total += i; } else if (i % 5 == 0 || i % 7 == 1) { total += i / 2; } } for (long i = start; i <= end; i += 1) { if (i % 2 == 0 || i % 3 == 1) { total -= i; } else if (i % 5 == 0 || i % 7 == 1) { total -= i / 2; } } return total; } int main() { printf("sum(0, 1000000000): %ld", sum(0, 100000000)); emscripten_exit_with_live_runtime(); return 0; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <stdio.h>
#include <emscripten.h>
 
long EMSCRIPTEN_KEEPALIVE sum(long start, long end) {
// long sum(long start, long end) {
  long total = 0;
  for (long i = start; i <= end; i += 1) {
    if (i % 2 == 0 || i % 3 == 1) {
      total += i;
    } else if (i % 5 == 0 || i % 7 == 1) {
      total += i / 2;
    }
  }
  for (long i = start; i <= end; i += 1) {
    if (i % 2 == 0 || i % 3 == 1) {
      total -= i;
    } else if (i % 5 == 0 || i % 7 == 1) {
      total -= i / 2;
    }
  }
  return total;
}
 
int main() {
  printf("sum(0, 1000000000): %ld", sum(0, 100000000));
  emscripten_exit_with_live_runtime();
  return 0;
}

执行

JavaScript

emcc sum.c -o sum.html

1
emcc sum.c -o sum.html

然后在sum.html中增加代码``

JavaScript

<button onclick="nativeSum()">NativeSum</button> <button onclick="jsSumCalc()">JSSum</button> <script type='text/javascript'> function nativeSum() { t1 = Date.now(); const result = Module.ccall('sum', 'number', ['number', 'number'], [0, 100000000]); t2 = Date.now(); console.log(`result: ${result}, cost time: ${t2 - t1}`); } </script> <script type='text/javascript'> function jsSum(start, end) { let total = 0; for (let i = start; i <= end; i += 1) { if (i % 2 == 0 || i % 3 == 1) { total += i; } else if (i % 5 == 0 || i % 7 == 1) { total += i / 2; } } for (let i = start; i <= end; i += 1) { if (i % 2 == 0 || i % 3 == 1) { total -= i; } else if (i % 5 == 0 || i % 7 == 1) { total -= i / 2; } } return total; } function jsSumCalc() { const N = 100000000;// 总次数1亿 t1 = Date.now(); result = jsSum(0, N); t2 = Date.now(); console.log(`result: ${result}, cost time: ${t2 - t1}`); } </script>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<button onclick="nativeSum()">NativeSum</button>
  <button onclick="jsSumCalc()">JSSum</button>
  <script type='text/javascript'>
    function nativeSum() {
      t1 = Date.now();
      const result = Module.ccall('sum', 'number', ['number', 'number'], [0, 100000000]);
      t2 = Date.now();
      console.log(`result: ${result}, cost time: ${t2 - t1}`);
    }
  </script>
  <script type='text/javascript'>
    function jsSum(start, end) {
      let total = 0;
      for (let i = start; i <= end; i += 1) {
        if (i % 2 == 0 || i % 3 == 1) {
          total += i;
        } else if (i % 5 == 0 || i % 7 == 1) {
          total += i / 2;
        }
      }
      for (let i = start; i <= end; i += 1) {
        if (i % 2 == 0 || i % 3 == 1) {
          total -= i;
        } else if (i % 5 == 0 || i % 7 == 1) {
          total -= i / 2;
        }
      }
 
      return total;
    }
    function jsSumCalc() {
      const N = 100000000;// 总次数1亿
      t1 = Date.now();
      result = jsSum(0, N);
      t2 = Date.now();
      console.log(`result: ${result}, cost time: ${t2 - t1}`);
    }
  </script>

别的,大家修改成编译成WebAssembly看看效果啊?

JavaScript

emcc sum.c -o sum.js -s WASM=1

1
emcc sum.c -o sum.js -s WASM=1
Browser webassembly asm.js js
Chrome61 1300ms 600ms 3300ms
Firefox55 600ms 800ms 700ms
Safari9.1 不支持 2800ms 因不支持ES6我懒得改写没测试

深感Firefox有一点不客观啊, 暗许的JS太强了呢。然后认为webassembly也远非极度强啊,陡然开掘emcc编写翻译的时候从不点名牌产品优品化增选-O2。再来贰次:``

JavaScript

emcc -O2 sum.c -o sum.js # for asm.js emcc -O2 sum.c -o sum.js -s WASM=1 # for webassembly

1
2
emcc -O2 sum.c -o sum.js # for asm.js
emcc -O2 sum.c -o sum.js -s WASM=1 # for webassembly
Browser webassembly -O2 asm.js -O2 js
Chrome61 1300ms 600ms 3300ms
Firefox55 650ms 630ms 700ms

居然没什么变化, 大失所望。堪当asm.js能够达到规定的规范native的二分之一速度么,那么些倒是好像达到了。可是现年Compiling for the Web with WebAssembly (Google I/O ‘17)里说WebAssembly是1.2x slower than native code,以为不对头呢。asm.js还应该有一个实惠是,它正是js,所以即使浏览器不支持,也能算作区别的js实施,只是未有加快效果。当然WebAssembly屡遭各大商家意气风发致重申,作为三个新的行业内部,肯定前景会越来越好,期望会有越来越好的显现。

Rust

自然还想写Rust编写翻译成WebAssembly的,然而感到本文已经太长了, 前期再写假若结合Rust做WebAssembly吧。

等比不上的能够先看看这两篇

  • Compiling to the web with Rust and emscripten
  • Rust ⇋ JavaScript

Refers

  • 1 赞 收藏 评论

图片 5

本文由IT-综合发布,转载请注明来源:前端高性能计算之二,前端高性能计算之一