【问题标题】:Node.js can't read python subprocess stdout when it read from stdin从标准输入读取时,Node.js 无法读取 python 子进程标准输出
【发布时间】:2016-11-24 16:58:19
【问题描述】:

我有一个 node.js 脚本,它启动一个 python 子进程并读取它的标准输出。只要 python 进程不尝试从标准输入读取,这就会起作用。那么父进程就不会从子进程那里得到任何东西。

我这里有 node.js 脚本和两个 python 测试用例:(如果你注释试图从标准输入读取的行,这两个例子都有效)

第一个孩子:

import sys

print('before')

for line in sys.stdin:
    print(line)

print('after')

第二个孩子:

import sys 

print('before')

while True:
    line = sys.stdin.readline()

    if line != '':
        print(line)
    else:
        break

print('after')

家长:

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

let client = spawn('python', ['test1.py'], {cwd: '/tmp'});

client.stdout.on('data', (data) => {
  console.log(data.toString());
});

client.stderr.on('data', (data) => {
  console.log(data.toString());
});

client.on('close', () => {
  console.log('close');
});

client.on('exit', () => {
  console.log('exit');
});


client.on('disconnect', () => {
  console.log('disconnect');
})

【问题讨论】:

  • 我不知道 node.js,但从 python 的角度来看,写了一行,但由于它是一个管道,而不是一个 tty,它被缓冲等待更多数据。您可以立即发送print('before', flush=True)。然后它等待数据......好吧......你需要发送数据。
  • flush=True 技巧确实解决了这个问题。如果您将此作为答案发布,我会接受它:)
  • node.js 端使用const spawn = require('pty.js').spawn; 之类的东西来解决这个问题可能会更好。这个问题讨论了拆分stdout/err 流*.com/questions/15339379/…。我很乐意提供答案……但我不确定它是否是最佳答案。
  • ...输入错误。那是'pty.js'

标签: python node.js process stdout stdin


【解决方案1】:

进程stdout 可以是无缓冲的、行缓冲的或块缓冲的,具体取决于进程的启动方式。特别是,从控制台启动的程序是行缓冲的,其标准输出被重定向(到管道或文件)的程序是块缓冲的。这样做是为了有效地增加整体程序。人们希望立即看到内容,因此终端是行缓冲的,但其他程序和文件可以等待并以更大的块获取内容,因此它们是块缓冲的。

您可以通过强制在每次写入时对数据进行flushhed 来解决python 端的问题。您可以使用 print 语句或 sys.stdout 对象本身来做到这一点

print('line 1', flush=True)
print('line 2')
print('line 3')
sys.stdout.flush()

您还可以通过模拟终端在 node.js 端修复它,基本上是欺骗程序认为它正在向用户显示。

const spawn = require('pty.js').spawn;

这是更通用的 - 您不需要孩子的合作即可使其发挥作用。但它可能会变得复杂。一些子进程获取有关附加 tty 的信息以执行更复杂的操作,例如创建菜单或颜色输出。但它通常是一个不错的选择。

【讨论】:

  • 感谢您的回答。 pty 解决方案有效,但我想再看一下第一个想法。当我刷新标准输出时,我可以接收来自 python 的输出,但我有另一个问题:当我使用 client.stdin.write('test') 向子进程发送文本时,这不会出现在 python 程序中。我是否也必须以某种方式刷新stdin
  • 我想是的。我真的不知道 node.js 但是如果 spawn 设置了一个到子标准输入的管道,它的块被缓冲并且有同样的问题。由于您正在阅读行,因此还需要包含换行符。