读取没有缓冲的子进程的stdout

时间:2014-06-11 13:02:08

标签: node.js socket.io

我试图读取Node.js到达时启动的Python脚本的输出。但是,只有在流程完成后才能访问数据。

var proc, args;

args = [
    './bin/build_map.py',
    '--min_lon',
    opts.sw.lng,
    '--max_lon',
    opts.ne.lng,
    '--min_lat',
    opts.sw.lat,
    '--max_lat',
    opts.ne.lat,
    '--city',
    opts.city
];

proc = spawn('python', args);

proc.stdout.on('data', function (buf) {
    console.log(buf.toString());
    socket.emit('map-creation-response', buf.toString());
});

如果我使用{stdio:'继承'我可以直接在控制台中看到输出。但是做一些像process.stdout.on(' data',...)这样的东西是行不通的。

如何确保我可以在子进程到达时读取子进程的输出并将其指向其他位置?

3 个答案:

答案 0 :(得分:1)

进行缓冲的过程是python,因为它知道终端已被重定向而不是真正去终端。您可以轻松地告诉Python not 进行此缓冲:只需运行“ python -u”而不是“ python”。那样应该很容易。

答案 1 :(得分:0)

child_process.spawn()生成进程时,连接到子进程的标准输出和标准错误的流实际上在Nodejs端没有缓冲。为了说明这一点,请考虑以下程序:

const spawn = require('child_process').spawn;

var proc = spawn('bash', [
  '-c',
  'for i in $(seq 1 80); do echo -n .; sleep 1; done'
]);

proc.stdout
.on('data', function (b) {
  process.stdout.write(b);
})
.on('close', function () {
  process.stdout.write("\n");
});

此程序运行bash,并使其每秒发出.个字符,持续80秒,同时通过data事件使用此子进程的标准输出。您应该注意到,Node程序每秒发射一次点,这有助于确认Nodejs端没有发生缓冲。

此外,如child_process上的Nodejs文档所述:

  

默认情况下,用于stdin,stdout和stderr的管道建立在   父Node.js进程和生成的子进程。有可能   通过这些管道以非阻塞方式传输数据。请注意,   一些程序在内部使用行缓冲I / O。虽然那样   不会影响Node.js,这可能意味着数据已发送到子进程   可能不会立即被消耗掉。

您可能要确认您的Python程序没有缓冲其输出。如果您感觉要从Python程序中发出数据时,是对标准输出的不同写操作,请考虑在每次写操作之后运行sys.stdout.flush(),以建议Python实际上应该写数据而不是尝试对其进行缓冲。

更新:在this commit中,出于以下原因,删除了Nodejs文档中的段落:

  

doc:删除有关子进程stdio的混乱注释

     

该段应该说什么并不明显。尤其是,   一个进程是否以及使用哪种缓冲机制   通常,stdio流不会影响到   关于它何时使用发送给它的数据。

这表明在Nodejs进程接收数据之前可能存在缓冲。尽管如此,应注意确保Nodejs上游控件中的进程不会缓冲其输出。

答案 2 :(得分:-4)

我注意到了节点spawn方法的以下行为。

我们假设我们有一个名为echo.sh的bash脚本:

#!/bin/bash

echo 1
echo 2

exit 0

和名为test.js的节点脚本:

require('child_process').spawn('./echo.sh').stdout.on('data', function(data) {
    console.log(data.toString());
    console.log('---------------');
});

现在让我们运行test.js

$ node test.js
1
2

---------------

没什么有趣的。

但是,如果我们修改echo.sh并在echo 1echo 2之间添加一些延迟(0.1秒):

#!/bin/bash

echo 1
sleep 0.1
echo 2

exit 0

结果不同:

$ node test.js 
1

---------------
2

---------------

正如您所看到的那样,spawn回调被调用两次,这正是您所需要的。我不确定这是否适用于Python,但我的建议是在您要广播的每个操作后为build_map.py添加延迟。也许这样你就能实现自己想要的目标。

祝你好运!