快捷搜索:
来自 新京葡娱乐场网址 2019-07-04 11:53 的文章
当前位置: 67677新澳门手机版 > 新京葡娱乐场网址 > 正文

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

前端高质量总结之一: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倍左右,当然依然得看本人计算机CPU的核数。 别的小编后来在同一的管理器上Firefox55.0.3(61位)测验,上诉代码居然只要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));

本文由67677新澳门手机版发布于新京葡娱乐场网址,转载请注明出处:前端高性能计算之二,前端高性能计算之一

关键词: