跨线程消息

跨线程消息

开启新的线程伴随而来的问题就是通讯问题。webworker 的 postMessage 可以帮助我们完成通信,但是这种通信机制是将数据从一部分内存空间复制到主线程的内存下。这个赋值过程就会造成性能的消耗。而共享内存,顾名思义,可以让我们在不同的线程间,共享一块内存,这些现成都可以对内存进行操作,也可以读取这块内存。省去了赋值数据的过程,不言而喻,整个性能会有较大幅度的提升。

postMessage

创建完毕之后,我们主要依靠 postMessage 与 onmessage 回调来在 Worker 线程与 UI 线程之间进行消息传递:
1
// worker.js
2
// 向主线程发送消息
3
postMessage('event from worker');
4
// 接收来自主线程的消息
5
onmessage = function(event) {};
6
7
// UI
8
worker.onmessage = function(event) {};
9
worker.postMessage('event from ui');
10
11
// 关闭当前 worker
12
worker.terminate();
Copied!
主线程与 Web Workers 之间的通信,并不是对象引用的传递,而是序列化/反序列化的过程,当对象非常庞大时,序列化和反序列化都会消耗大量计算资源,降低运行速度。
1
// main
2
var worker = new Worker('./worker.js');
3
4
worker.onmessage = function getMessageFromWorker(e) {
5
// 被改造后的数据,与原数据对比,表明数据是被克隆了一份
6
console.log('e.data', ' -- ', e.data);
7
// [2, 3, 4]
8
9
// msg 依旧是原本的 msg,没有任何改变
10
console.log('msg', ' -- ', msg);
11
// [1, 2, 3]
12
};
13
14
var msg = [1, 2, 3];
15
16
worker.postMessage(msg);
17
18
// worker
19
onmessage = function(e) {
20
var newData = increaseData(e.data);
21
postMessage(newData);
22
};
23
24
function increaseData(data) {
25
for (let i = 0; i < data.length; i++) {
26
data[i] += 1;
27
}
28
29
return data;
30
}
Copied!
由上述代码可知,每一个消息内的数据在不同的线程中,都是被克隆一份以后再传输的。数据量越大,数据传输速度越慢。

sharedBufferArray

对象转移使用方式很简单,给 postMessage 增加一个参数,把对象引用传过去即可:
1
var ab = new ArrayBuffer(1);
2
worker.postMessage(ab, [ab]);
Copied!
1
// main.js
2
var worker = new Worker('./sharedArrayBufferWorker.js');
3
4
worker.onmessage = function(e) {
5
// 传回到主线程已经被计算过的数据
6
console.log('e.data', ' -- ', e.data);
7
// SharedArrayBuffer(3) {}
8
9
// 和传统的 postMessage 方式对比,发现主线程的原始数据发生了改变
10
console.log('int8Array-outer', ' -- ', int8Array);
11
// Int8Array(3) [2, 3, 4]
12
};
13
14
var sharedArrayBuffer = new SharedArrayBuffer(3);
15
var int8Array = new Int8Array(sharedArrayBuffer);
16
17
int8Array[0] = 1;
18
int8Array[1] = 2;
19
int8Array[2] = 3;
20
21
worker.postMessage(sharedArrayBuffer);
22
23
// worker.js
24
onmessage = function(e) {
25
var arrayData = increaseData(e.data);
26
postMessage(arrayData);
27
};
28
29
function increaseData(arrayData) {
30
var int8Array = new Int8Array(arrayData);
31
for (let i = 0; i < int8Array.length; i++) {
32
int8Array[i] += 1;
33
}
34
35
return arrayData;
36
}
Copied!
通过共享内存传递的数据,在 worker 中改变了数据以后,主线程的原始数据也被改变了。
Last modified 2yr ago