Node 并行处理时共享变量需注意

这个周在工作的时候遇到了一个奇怪的bug,找了很久,发现是并行计算的时候某个共享的对象变量会被篡改的原因

先直接上代码:

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
39
40
41
42
43
44
45
46
47
48
const Promise = require('bluebird');
const _ = require('loadsh');

function testForObject (obj, change) {
console.log(`=====berfore: ${obj.test}=============`);
obj.test = change;
console.log(`=====after: ${obj.test}=============`);
}

function testForCloneObject (obj, change) {
let cloneObj = _.cloneDeep(obj);
console.log(`=====berfore: ${cloneObj.test}=============`);
cloneObj.test = change;
console.log(`=====after: ${cloneObj.test}=============`);
}

const start = async function () {
const extParams = {
test: 10
}
const indexs = [1, 2];
Promise.map(indexs, (index) => {
testForObject(extParams, index);
}, {concurrency: 3});
}


const start2 = async function () {
const extParams = {
test: 10
}
const indexs = [1, 2];
Promise.map(indexs, (index) => {
testForCloneObject(extParams, index);
}, {concurrency: 3});
}

start();
// =====berfore: 10=============
// =====after: 1=============
// =====berfore: 1=============
// =====after: 2=============

start2();
// =====berfore: 10=============
// =====after: 1=============
// =====berfore: 10=============
// =====after: 2=============

根据结果我们可以看到,如果传入的变量没有经过深复制,不同进程之间对于同一个传入的对象变量的修改会相互影响,这是因为在js中对象变量在传参时传入的是引用,所以如果你对于某个传入的对象参数直接修改,就会导致这种情况。

而且这种情况下,即使你传入的对象参数是const也是没有用的,因为const只是保证了该变量的引用地址是不变的,对于地址中保存的值是没有约束的。

最好的方法就是参数传入之后直接进行深复制。