解析nodejs的child_process之fork

child_process 是nodejs 的子进程通讯模块,官方文档精简,这里写一个初步应用作为参考

注意,本文使用es6语法书写

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
const fork = require('child_process').fork;
//创建进程,一般视cpu核数而定
const os = require('os');
const task_num = os.cpus().length;

//要发送给子进程来处理的数据
let data = [1,2,3,4,5,6,7,8];
//有多少任务就把数据分成多少份
//这里写一个方法分割数据
function chunk(array)
{
let chunk = os.cpus().length;
let result = [];
let num = Math.ceil(array.length/chunk);

for(let i = 0; i < array.length; i += num)
{
result.push( array.slice(i, i + num ) );
}

return result;

}

data = chunk(data);

//初始化任务的个数
let task = task_num;

//设置任务重试,如果任务失败,记录该任务,在重试次数过后还是失败则为真的失败
let retry = new Map();
let retry_time = 3;
[...Array(task_num).keys()].map((num)=>{
//创建子进程,传递参数给子进程
//相当于node child_script num
let c = fork('./child_script',[num]);
//发送数据给子进程
//确认当前进程要处理的任务数
let cnum = data[num].length;
c.send({ data : data[num] });

//监听子进程消息
c.on('message', (m)=>{
//每次收到信息,假设任务已经被处理
cnum--;

//子进程无论处理成功或失败都要通知主进程
if(m.err)
{
if(!retry.has(m.data) || (retry.has(m.data) && retry.get(m.data) < retry_time ))
{
cnum++;
c.send({data: m.data});
retry.set(m.data, !retry.has(m.data) ? 1 : retry.get(m.data) + 1);
}else{
//已经失败三次,放弃处理
}
}else{
//正确处理
}
console.log(m);
//任务全部处理结束,发送信号给子进程,子进程接收到信号后退出,并触发exit事件
if(!cnum){
c.kill('SIGTERM');
}
});

//监听子进程退出事件
c.on('exit', ()=>{
//子进程退出,当前的总任务数减少
task--;
console.log('task closed. num: ', num);
if(!task){
//这里做你想要做的事,如果这个任务在promise里,那么resolve()
}
});

//监听错误
c.on('error', (e)=>{
console.log('err', e)
});
});
  • 子进程不要处理完自行退出,虽然主进程可以监听到子进程的exit事件,但是可能还未接收到消息,子进程一旦退出,则再也无法接收到子进程的消息了
  • 重试不是必须的,但是有时因为网络自身的问题,如果不重试,等任务跑完,这些原本是可以成功处理的数据又要再处理一次,岂不麻烦

子进程使用process模块,这里举一个简单的例子,check网页是否404

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const exec = require('child_process').execSync;
//主进程传送过来的参数,这里只取第一个参数
const task = process.argv[2];

const url = 'http://localhost/post/';

process.on('message', (m)=>{
m.data.map(($post_id)=>{
let result = exec(`curl -s -o /dev/null -I -w "${http_code}" ${url + $post_id}`);
result = result.toString();
if(result == 404){
console.log('err', $post_id);
process.send({data: $post_id, err : 1});
}else{
console.log('success', $post_id);
}
});
})

这是一个简单的批量check页面是否404应用,但是相信能帮助很多人愉快地凌辱这个模块

#

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×