有没有办法让子进程输出流更频繁地刷新其数据?

时间:2017-11-15 21:59:08

标签: node.js

我正在尝试管理一个子流程'标准输出到父母的标准输出:

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

有没有办法让子输出流使用较小的缓冲区或更频繁地刷新?

1 个答案:

答案 0 :(得分:3)

操作系统和子进程控制输出缓冲。

例如,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()

如果正在运行的子进程没有等效选项或配置来刷新输出,则this Unix + Linux question包括许多技巧,通过修改子进程的运行方式来禁用缓冲输出,通过分配伪终端或直接修改它的缓冲区。

还有node-ptynode-pty2,它们将使用伪终端生成进程,这类似于期望unbuffer命令的进程。我之前没有使用任何一个模块,所以不能保证它们。