Child Process
Child Process
child_process 这个模块可以生成一个子进程。nodejs提供了好几个API,本质上都是调用child_process.spawn():
const spawn = require('child_process').spawn;
const ls = spawn('ls', ['-lh', '/usr']);
ls.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
});
ls.stderr.on('data', (data) => {
console.log(`stderr: ${data}`);
});
ls.on('close', (code) => {
console.log(`child process exited with code ${code}`);
});
默认情况下:stdin, stdout and stderr 这3个管道会链接在父进程和子进程之间!这使得父子进程数据流的交互畅通无阻。注意:有些程序自身内部利用了I/0
Buffer,但是这并不影响Node.js. 它只是意味着父进程发送数据给子进程不能马上消耗掉而已。
Nodejs为了方便大家使用,提供了很多同步与异步的方法,本文只介绍异步的!异步的优点就是不会阻塞Nodejs的事件循环。
child_process.exec(): spawns a shell and runs a command within that shell, passing thestdoutandstderrto a callback function when complete.child_process.execFile(): similar tochild_process.exec()except that it spawns the command directly without first spawning a shell.child_process.fork(): spawns a new Node.js process and invokes a specified module with an IPC communication channel established that allows sending messages between parent and child.child_process.execSync(): a synchronous version ofchild_process.exec()that will block the Node.js event loop.child_process.execFileSync(): a synchronous version ofchild_process.execFile()that will block the Node.js event loop.
child_process.spawn(), child_process.fork(), child_process.exec(), and child_process.execFile()
都会返回一个ChildProcess 实例。ChildProcess 实现了NodejsEventEmitter的 API,允许父进程注册监听函数,在子进程的生命周期内发生指定事件的时候调用。
child_process.exec() and child_process.execFile()还额外提供了callback选项,当子进程终止的时候调用!
Spawning .bat and .cmd files on Windows
child_process.exec() and child_process.execFile()最大的区别无疑是基于的平台不同!
在 Unix-type 这样类型的操作系统上 (Unix, Linux, OSX) ,child_process.execFile() 跑起来更高效,因为他不需要生成一个shell.
然后在Windows上,.bat and .cmd文件是无法离开终端独立执行的,玩Windows的同志只能用child_process.exec()来执行批处理文件。
或者说利用child_process.spawn() 配置项里设置shell.
或者说利用生成一个cmd.exe ,然后传 .bat or .cmd文件名作为参数。这里关键了。一定要带上 /? 不然在你无法生成一个新的shell实例。
// On Windows Only ...
const spawn = require('child_process').spawn;
const bat = spawn('cmd.exe', ['/c', 'my.bat']); bat.stdout.on('data', (data) => {
console.log(data);
}); bat.stderr.on('data', (data) => {
console.log(data);
}); bat.on('exit', (code) => {
console.log(`Child exited with code ${code}`);
}); // OR...
const exec = require('child_process').exec;
exec('my.bat', (err, stdout, stderr) => {
if (err) {
console.error(err);
return;
}
console.log(stdout);
}); // Script with spaces in the filename:
const bat = spawn('"my script.cmd"', ['a', 'b'], { shell:true });
// or:
exec('"my script.cmd" a b', (err, stdout, stderr) => {
// ...
});
child_process.exec(command[, options][, callback])
command<String> The command to run, with space-separated argumentsoptions<Object>cwd<String> Current working directory of the child processenv<Object> Environment key-value pairsencoding<String> (Default:'utf8')shell<String> Shell to execute the command with (Default:'/bin/sh'on UNIX,'cmd.exe'on Windows, The shell should understand the-cswitch on UNIX or/d /s /con Windows. On Windows, command line parsing should be compatible withcmd.exe.)timeout<Number> (Default:0)maxBuffer<Number> largest amount of data (in bytes) allowed on stdout or stderr - if exceeded child process is killed (Default:200*1024)killSignal<String> (Default:'SIGTERM')uid<Number> Sets the user identity of the process. (See setuid(2).)gid<Number> Sets the group identity of the process. (See setgid(2).)
callback<Function> called with the output when process terminates- Returns: <ChildProcess>
{
encoding: 'utf8',
timeout: 0,
maxBuffer: 200*1024,
killSignal: 'SIGTERM',
cwd: null,
env: null
}
注意回调里的3个参数,如果指定了encoding,那就是String,不然就是buffer。
timeout(如果大于0) 是为了规定子进程的执行时间,如果超过了,这时候就会用到 killSignal 属性了,默认父进程发送的是 'SIGTERM'。
不同于exec(3) POSIX,child_process.exec() 是不会取代已经存在的进程的,使用shell来执行命令。
child_process.execFile(file[, args][, options][, callback])
file<String> The name or path of the executable file to runargs<Array> List of string argumentsoptions<Object>cwd<String> Current working directory of the child processenv<Object> Environment key-value pairsencoding<String> (Default:'utf8')timeout<Number> (Default:0)maxBuffer<Number> largest amount of data (in bytes) allowed on stdout or stderr - if exceeded child process is killed (Default:200*1024)killSignal<String> (Default:'SIGTERM')uid<Number> Sets the user identity of the process. (See setuid(2).)gid<Number> Sets the group identity of the process. (See setgid(2).)
callback<Function> called with the output when process terminates- Returns: <ChildProcess>
child_process.execFile()和child_process.exec()很像,除了 child_process.execFile() 执行的时候不会生成新的shell,这个指定的file将会被执行作为新进程。 这一点比child_process.exec() 更有效率。
这里部分一点:
开始学习child_process模块的时候以为spawn可以直接运行命令, 后来发现这是一个小陷阱就拿出来和大家分享一下.
先说下我碰到的情况由于在windos下写的所以根据docs上的例子我就写出了这么一句代码:"require(“child_process”).spawn(“dir”), 这么写是会有错误的,用error接受到的数据是没有此文件. 而用exec就不会有问题,于是得到了以前的猜想.
大家都知道在linux下, ls命令对应的是一个文件, 而在windows下是做为cmd的内置命令的. 所以像我那样写是会报错.
于是我查看了child_process的源码发现spawn是这样定义的var spawn = exports.spawn = function(file, args, options); 也就是说他传入的应该是一个文件, 例如ping, cmd等. 而exec的源码中有一段这样的代码:
if (process.platform === 'win32') {
file = 'cmd.exe';
args = ['/s', '/c', '"' + command + '"'];
// Make a shallow copy before patching so we don't clobber the user's
// options object.
options = util._extend({}, options);
options.windowsVerbatimArguments = true;
} else {
file = '/bin/sh';
args = ['-c', command];
}
所以想使用内置命令可以直接使用exec或者把spawn改成spawn(“cmd.exe”,["\s", “\c”, “dir”]);
总结起来就是spawn是调用一个文件! 不要被docs上的child_process.spawn(command, [args], [options])中的command给骗了
-----------------------------------------------------------------------------------------------
options.detached
在windows上,设置options.detached 为 true,可以保证父进程退出的时候,子进程还可以运行,子进程拥有自己的console窗口,一旦启动,就不可能停止。
非windows的话,设置options.detached 为 true,子进程将会新进程的控制者,不管父子进程有没有设置detached ,子进程都可以在父进程退出后保存运行!
默认情况下 ,父进程需要等子进程运行完毕才离开,但是我们可以调用child.unref() 来避免发生!这样允许父进程和子进程独立开来,除非他们建立了IPC信道。
看一眼为什么:
针对handle而言,判断loop是否存活只要看loop->active_handles是否大于0,大于0则存活。
具体代码参看 https://github.com/libuv/libuv/blob/v1.x/src/uv-common.h
uv__handle_init, uv__handle_start, uv__handle_stop, uv__handle_ref, uv__handle_unref
比较下面几种情况,可能会有利于理解unref的作用。
第一种
var timer1 = setTimeout(function(){
console.log(new Date, 1);
}, 1000);
// setTimeout=>uv_timer_start(timer1) active_handles = 1
var timer2 = setInterval(function(){
console.log(new Date, 2);
}, 1000);
// setInterval=>uv_timer_start(timer2) active_handles = 2
// 1: ative_handles > 0 => loop()
// timer1 timeout => uv_timer_stop(timer1) active_handles = 1 => callback()
// timer2 timeout => uv_timer_stop(timer2) active_handles = 0 => callback() => uv_timer_start(timer2) active_handles = 1
// 2: active_handles > 0 => loop()
// timer2 timeout => uv_timer_stop(timer2) active_handles = 0 => callback() => uv_timer_start(timer2) active_handles = 1
// goto 2
第二种
var timer1 = setTimeout(function(){
console.log(new Date, 1);
}, 1000);
// setTimeout=>uv_timer_start(timer1) active_handles = 1
var timer2 = setInterval(function(){
console.log(new Date, 2);
}, 1000);
// setInterval=>uv_timer_start(timer2) active_handles = 2
timer2.unref();
// uv_unref(timer2) active_handles = 1
// ative_handles > 0 => loop()
// timer1 timeout => uv_timer_stop(timer1) active_handles = 0 => callback()
// timer2 timeout => uv_timer_stop(timer2) active_handles = 0 => callback() => uv_timer_start(timer2) active_handles = 0
// active_handles == 0 => exit_process
第三种
var timer1 = setInterval(function(){
console.log(new Date, 1);
}, 1000);
// setInterval=>uv_timer_start(timer1) active_handles = 1
var timer2 = setInterval(function(){
console.log(new Date, 2);
}, 1000);
// setInterval=>uv_timer_start(timer2) active_handles = 2
// 1: ative_handles > 0 => loop()
// timer1 timeout => uv_timer_stop(timer1) active_handles = 1 => callback() => uv_timer_start(timer1) active_handles = 2
// timer2 timeout => uv_timer_stop(timer2) active_handles = 1 => callback() => uv_timer_start(timer2) active_handles = 2
// goto 1
第四种
var timer1 = setInterval(function(){
console.log(new Date, 1);
}, 1000);
// setInterval=>uv_timer_start(timer1) active_handles = 1
var timer2 = setInterval(function(){
console.log(new Date, 2);
}, 1000);
// setInterval=>uv_timer_start(timer2) active_handles = 2
timer2.unref()
// uv_unref(timer2) active_handles = 1
// 1: ative_handles > 0 => loop()
// timer1 timeout => uv_timer_stop(timer1) active_handles = 0 => callback() => uv_timer_start(timer1) active_handles = 1
// timer2 timeout => uv_timer_stop(timer2) active_handles = 1 => callback() => uv_timer_start(timer2) active_handles = 1
// goto 1
第五种
var timer1 = setInterval(function(){
console.log(new Date, 1);
}, 1000);
// setInterval=>uv_timer_start(timer1) active_handles = 1
timer1.unref()
// uv_unref(timer1) active_handles = 0
var timer2 = setInterval(function(){
console.log(new Date, 2);
}, 1000);
// setInterval=>uv_timer_start(timer2) active_handles = 1
timer2.unref()
// uv_unref(timer2) active_handles = 0
// ative_handles == 0 => exit process
--------------------------------------------------------------------------
最后总结:4个方法其实大同小异,最后其实都是调用spawn,需不需要用shell,完全看你的file是不是需要在shell 上运行,最后注意一下
maxBuffer and Unicode
这个属性最好你别设置,stdout,stdin stderr里的buffer量超出了,child process就鸡鸡了。
Child Process的更多相关文章
- wireshark_Couldn’t run /usr/sbin/dumpcap in child process: Permission denied
关于Wireshark出现:Couldn't run /usr/sbin/dumpcap in child process: Permission denied Are you a member of ...
- innobackupex:Error:xtrabackup child process has died at /usr/bin/innobackupex
使用innobackupex进行数据库备份,报如下错误:innobackupex --compress --parallel=4 --user=root --password=yoon /expo ...
- nodejs child process
//Create child processvar thread = require('child_process'); var msg = thread.fork(__dirname + '/chi ...
- 【笔记】mongodb启动不了:child process failed, exited with error number 100
今天在启动mongodb的时候,发现起不来,报错:child process failed, exited with error number 100然后先去/var/log/mongo/mongod ...
- Wireshark:couldn't run dumpcap in child process(附带Linux下探索过程)
之前都是直接使用Kali里面安装好的Wireshark和Win下的,Ubuntu的来个小计 PS:解决方法不重要,我觉得更重要的是这个摸索的过程 解决方法 # 安装wireshark sudo apt ...
- Mongodb中经常出现的错误(汇总)child process failed, exited with error number
异常处理汇总-服 务 器 http://www.cnblogs.com/dunitian/p/4522983.html 异常处理汇总-数据库系列 http://www.cnblogs.com/dun ...
- Child Process模块
目录 exec() execSync() execFile() spawn() fork() send() 参考链接 child_process模块用于新建子进程.子进程的运行结果储存在系统缓存之中( ...
- ERROR: child process failed, exited with error number 100
[root@localhost ~]# mongod --dbpath=/usr/local/mongodb/data --logpath=/usr/local/mongodb/logs --loga ...
- node中非常重要的process对象,Child Process模块
node中非常重要的process对象,Child Process模块Child Process模块http://javascript.ruanyifeng.com/nodejs/child-proc ...
随机推荐
- Python爬虫使用Selenium+PhantomJS抓取Ajax和动态HTML内容
1,引言 在Python网络爬虫内容提取器一文我们详细讲解了核心部件:可插拔的内容提取器类gsExtractor.本文记录了确定gsExtractor的技术路线过程中所做的编程实验.这是第二部分,第一 ...
- 负载均衡集群之LVS的DR模型详解(Diretor Routing)
LVS的默认模型:默认模型DR DR模型原理图--> 在讲DR模型要点之前,需要了解网络的相关知识: 接收的报文拆解顺序:帧(MAC)-->数据包(IP)-->数据报文(port) ...
- query通用开源框架
Jquery通用开源框架之[ejq.js] 简介 ejq是一款非常小巧的JS工具库,未压缩才50K,在jquery的基础上对jquery缺失部分作了很好的弥补作用. 优点: 1.具有内置的模板解析引擎 ...
- QObject就有eventFilter,功能很强(随心所欲的进行处理,比如用来QLineEdit分词)
相信大家都用过词典吧!因为英语不太好...O(∩_∩)O~,所以经常进行划词翻译! 简述 实现 效果 源码 更多参考 实现 原理:鼠标移至某单词之上,获取鼠标位置,然后在对应位置进行取词,翻译! 基于 ...
- 《深入了解 Linq to SQL》之对象的标识 —— 麦叔叔呕心呖血之作
序言 很多朋友都向我提过,希望我写一下关于Linq to SQL 或者 VS 插件方面的文章.尽管市面上有很多 Linq to SQL 的书籍,但是都是介绍怎么用,缺乏深度.关于 VS 插件方面的书籍 ...
- 分治法求一个N个元素数组的逆序数
背景 逆序数:也就是说,对于n个不同的元素,先规定各元素之间有一个标准次序(例如n个 不同的自然数,可规定从小到大为标准次序),于是在这n个元素的任一排列中,当某两个元素的先后次序与标准次序不同时, ...
- Unity扩展让枚举视图中变成多选框
如图: 定义属性描述特性(因为没有描述的数据,让绘制类去绘制所以为空) using UnityEngine; using System.Collections; public class EnumFl ...
- poj1426 Find The Multiple
Find The Multiple Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 14622 Accepted: 593 ...
- mime大全收集
{"ai", "application/postscript"}, {"aif", "audio/x-aiff" ...
- 9.5 在 C# 中使用 F# 库
9.5 在 C# 中使用 F# 库 像 C# 一样,F# 也是一种静态类型的语言,就是说,编译器知道每一个值的类型,以及类方法和属性的签名.对于与 C# 的互操作性来说.这是很重要的,由于,编译器能够 ...