我正在尝试将子进程的标准输出管道传输到父进程的标准输出:
import {exec} from 'child_process';
console.log(new Date() + " starting")
const child = exec(/* some command */);
child.stdout.pipe(process.stdout);
这有效,但子进程相对于管道缓冲区的大小生成数据的速度非常慢。数据以大块的形式出现,并不频繁。
例如,如果我像这样观看子输出流:
child.stdout.on('data', data => console.log(new Date(), data.length));
输出为
2017-11-15T21:53:44.128Z starting
2017-11-15T21:53:58.319Z 8192
2017-11-15T21:54:02.321Z 8192
2017-11-15T21:54:07.384Z 8192
2017-11-15T21:54:11.333Z 8192
2017-11-15T21:54:15.281Z 8192
2017-11-15T21:54:19.008Z 3967
有没有办法让子输出流使用较小的缓冲区或更频繁地刷新?
操作系统和子进程控制输出缓冲。
例如,Python 有一个-u
选项,会导致写入被刷新(也是 PYTHONUNBUFFERED
env var(。以下改编自问题的示例显示了在使用无缓冲和正常输出时每秒写入整数以筛选的命令的行为差异。
const {exec} = require('child_process')
function run(cmd){
return new Promise((resolve, reject) => {
console.log("%s starting %s", Date.now(), cmd)
const child = exec(cmd)
child.stdout.pipe(process.stdout)
child.stderr.pipe(process.stderr)
child.on('exit', exit => {
console.log('%s exit', Date.now(), exit)
if ( exit === 0 ) return resolve(exit)
reject(new Error(exit))
})
})
}
async function go(){
await run('python -uc "import time; [print(i,str(time.sleep(1))) for i in range(10)]"')
await run('python -c "import time; [print(i,str(time.sleep(1))) for i in range(10)]"')
}
go()
如果正在运行的子进程没有等效的选项或配置来刷新输出,那么这个 Unix + Linux 问题包括许多技巧,通过修改子进程的运行方式来禁用缓冲输出,通过分配伪终端或直接修改它的缓冲区。
还有node-pty
和node-pty2
,它们将使用伪终端生成进程,这与unbuffer
命令的预期类似。我以前没有使用过这两个模块,所以不能保证它们。