Javascript 异步编程(下)

这是我参与更文挑战的第20天,活动详情查看: 更文挑战

原理

  • 为什么是单线程
  • 事件循环

image.png

I/O延迟

L1 3 cycles
L2 14 cycles
RAM 250 cycles
Disk 41,000,000
Network 240,000,000

image.png

image.png

image.png

为什么是单线程

  • 轻量
  • 简化并发模型,无死锁
  • 没有线程切换开销

事件循环

image.png

一次完成一个任务直到运行完成
image.png

Macrotask/Microtask

Macrotask Queue

Script标签、setTimeout、setinterval、setImmediate、requestAnimationFrame、I/O、UI渲染、异步ajax、用户事件、message channel

Microtask Queue

process.nextTick、Promise、Object.observe、
MutationObserver

例外

alert()、prompt()、confirm()
Sync AJAX

意外的多线程表现

setTimeout(() => {
  console.log('before alert');
  alert('Pause');
  console.log('after alert');
},100);

window.addEventListener('resize', () => {
  console.log('resize');
})

/*
    before alert
    after alert
    resize
*/

/*
    before alert
    resize
    after alert
*/

复制代码

window下,改小分辨率;
linux 下直接调整浏览器窗口尺寸。

异步事件同步触发

const input1 = document.getElementById('input1');
const input2 = document.getElementById('input2');
input1.addEventListener('blur',() => {
  console.log('blur');
});
setTimeout(() => {
  console.log('before');
  input2.focus();
  console.log('after');
},100);
input1.focus();
/*
    before
    after
    blur
*/

/*
    before
    blur
    after
*/
复制代码

运行时特性

  • Web Worker
  • Service Worker
  • Child_process(Node.js)
  • Cluster(Node.js)

web worker

  • 真正的多线程

  • 不共享内存,线程安全

  • 通过message channel传递数据

  • 无法使用window和document对象

// main.js

function run() {
  const worker = new Worker('bigLoop.js');
  worker.postMessage('start');
  worker.onmessage = result => {
    console.log(result);
    worker.terminate();
  };
}
run();
run();
run();
run();
console.log('hello world');
复制代码
// bigLoop.js

onmessage = () => {
  let j = 0;
  for (let i = 0; i<=1000000000; i+=1) {
    j += i;
    j *= -1;
  }
  postMessage(j);
};
复制代码

service worker

  • 充当页面与服务器之间的网络代理

  • 具有web worker 的特点

  • 仅支持https

  • 独立于页面存在

Child_process

  • 支持子进程

  • 通过IPC通道进行进程间通信

// parent.js

const {fork} = require('child_process');
const child = fork('./child.js');
child.on('message',m => {
  console.log(`message from child:${JSON.stringify(m)}`)
});
child.send({from: 'parent'});
复制代码
// child.js

process.on('message', m => {
  console.log(`message from parent: ${JSON.stringify(m)}`);
});
process.send({from: 'child'});
复制代码

cluster

const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;

if(cluster.isMaster) {
  console.log(`Master ${process.pid} is running`);

  // Fork workers.
  for(let i = 0; i < numCPUs; i++){
    cluster.fork();
  }

  cluster.on('exit',worker => {
    console.log(`worker ${worker.process.pid} died`);
  });
}
else {
  // Workers can share any TCP connection
  // In this case it is an HTTP server

  http.createServer((req,res) => {
    res.writeHead(200);
    res.end('hello world\n');
  }).listen(8000);

  console.log(`Worker ${process.pid} started`);
}
复制代码

延申

  • webGL

  • Web Assembly

  • Node.js C++ Addon

WebGL

加速矩阵运算示例

import GPU from 'gpu.js';
const gpu = new GPU();
const multiplyMatrixGPU = gpu.createKernel(function (a,b) {
  let sum = 0;
  for (let i = 0; i < 2048; i++) {
    sum += a[this.thread.y][i] * b[i][this.thread.x];
  }
  return sum;
}).setOutput([2048,2048]);

let now = performance.now();
const result1 = multiplyMatrixGPU(matrix1,matrix2);
console.log('GPU:',performance.now() - now, 'ms');

// GPU: 6207.63 ms
复制代码
function multiplyMatrixCPU(a,b) {
  const result = [];
  for (let i = 0; i < 2048; i++) {
    result[i] = [];
    for (let j = 0; j < 2048; j++) {
      let sum = 0;
      for (let k = 0; k < 2048; k++) {
        sum += a[i][k] * b[k][j];
      }
      result[i][j] = sum;
    }
  }
  return result;
}

let now = performance.now();
const result2 = multiplyMatrixCPU(matrix1,matrix2);
console.log('CPU:', performance.now() - now, 'ms');

// CPU: 111287.36ms
复制代码

Web Assembly

WebAssembly 是一种可以使用非 JavaScript 编程语言编写代码并且能在浏览器上运行的技术方案。

它是一种新的编码方式,一种低级的类汇编语言,当然此语言和JavaScript可以一起工作。

Node.js C++ Addon

// index.js

var primes = require('./build/Release/threads.node').primes;
primes(4);
复制代码
线程数 加速
1 1.75x
2 3.13x
3 2.84x
4 3.86x
8 2.43x
16 2.94x
32 2.07x
50 2.91x
100 1.85x
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享