事实证明这并不像我想象的那么简单。我想要做的是通过将Popen
命令设置为上一个命令的stdin
(或stdout
为第一个命令,使用PIPE
链接一些命令{1}})。另外,我将命令的stdin
设置为stderr
- ed files。
我所看到的是,在open
第一个命令的close
之前,基本上这根本不起作用。当我写入第一个命令stdin
时,我期待进程在管道链中进行通信,但在关闭第一个命令的stdin
之前,没有任何内容写入第二个命令。同样,在关闭第一个命令的stdin
之前,没有stderr
个文件实际写入。
请考虑以下示例:
stdin
./cat.py
和
#!/usr/bin/python3
import sys, datetime
def log(msg, file):
file.write(str(datetime.datetime.now()) + ': ' + msg + '\n')
log('starting now', sys.stdout)
log('rofl', sys.stderr)
for input_line in iter(sys.stdin.readline, ''):
input_line = input_line.rstrip('\n')
log(input_line, sys.stdout)
log('lol ' + input_line, sys.stderr)
log('ending now', sys.stdout)
./basic.py
这将启动一个4进程#!/usr/bin/python3
import sys, subprocess
subproc = []
length = 4
for i in range(0, length):
if i == 0:
subproc.append(subprocess.Popen('./cat.py', bufsize=0, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=open(str(i) + '.stderr', 'w')))
elif i == length - 1:
subproc.append(subprocess.Popen('./cat.py', bufsize=0, stdin=subproc[-1].stdout, stdout=open(str(i) + '.stdout', 'w'), stderr=open(str(i) + '.stderr', 'w')))
else:
subproc.append(subprocess.Popen('./cat.py', bufsize=0, stdin=subproc[-1].stdout, stdout=subprocess.PIPE, stderr=open(str(i) + '.stderr', 'w')))
for input_line in iter(sys.stdin.readline, ''):
input_line = input_line.rstrip('\n')
subproc[0].stdin.write((input_line + '\n').encode())
链并将Popen
写入stderr
,0.stderr
等,并将最终1.stderr
写入stdout
。输出行带有时间戳,因此您可以轻松验证特定子进程何时收到输入。从基本测试中考虑这些输出,我在输入之间等待了几秒钟。
3.stdout
0.stderr
2018-03-07 16:18:48.316847: rofl
2018-03-07 16:18:51.815376: lol hello 1
2018-03-07 16:18:55.561168: lol hello 2
2018-03-07 16:18:59.204273: lol hello 3
1.stderr
2018-03-07 16:18:48.320991: rofl
2018-03-07 16:19:01.888496: lol 2018-03-07 16:18:48.316825: starting now
2018-03-07 16:19:01.888508: lol 2018-03-07 16:18:51.815345: hello 1
2018-03-07 16:19:01.888515: lol 2018-03-07 16:18:55.561136: hello 2
2018-03-07 16:19:01.888523: lol 2018-03-07 16:18:59.204241: hello 3
2018-03-07 16:19:01.888531: lol 2018-03-07 16:19:01.886950: ending now
3.stdout
正如您所看到的,第一个子进程实时获取2018-03-07 16:18:48.323203: starting now
2018-03-07 16:19:01.899180: 2018-03-07 16:18:48.323766: starting now
2018-03-07 16:19:01.899208: 2018-03-07 16:19:01.895778: 2018-03-07 16:18:48.320973: starting now
2018-03-07 16:19:01.899216: 2018-03-07 16:19:01.895804: 2018-03-07 16:19:01.888476: 2018-03-07 16:18:48.316825: starting now
2018-03-07 16:19:01.899224: 2018-03-07 16:19:01.895813: 2018-03-07 16:19:01.888504: 2018-03-07 16:18:51.815345: hello 1
2018-03-07 16:19:01.899233: 2018-03-07 16:19:01.895820: 2018-03-07 16:19:01.888512: 2018-03-07 16:18:55.561136: hello 2
2018-03-07 16:19:01.899240: 2018-03-07 16:19:01.895829: 2018-03-07 16:19:01.888519: 2018-03-07 16:18:59.204241: hello 3
2018-03-07 16:19:01.899247: 2018-03-07 16:19:01.895836: 2018-03-07 16:19:01.888527: 2018-03-07 16:19:01.886950: ending now
2018-03-07 16:19:01.899254: 2018-03-07 16:19:01.895844: 2018-03-07 16:19:01.892480: ending now
2018-03-07 16:19:01.899262: 2018-03-07 16:19:01.895860: ending now
2018-03-07 16:19:01.899277: ending now
,然后链停止,直到我关闭第一个子进程的write
。尽管我使用stdin
进行所有bufsize=0
次调用,但仍然如此。 (不使用Popen
,在关闭0
之前,甚至第一个子流程都没有收到任何write
。)
我正在尝试做什么?这样做的正确方法是什么?
stdin
在我的情况下不起作用,因为该函数会关闭communicate
。我需要保持stdin
打开整个过程来处理其他传入数据。我需要保持第一个stdin
打开以接收额外的输入,同时命令的输出沿管道链发送,由下一个命令处理并在管道链中进一步发送。
有什么建议吗?
我使用的是Python 3.4.3。
谢谢,
答案 0 :(得分:0)
在进程之间传输数据非常昂贵(相对于进程中的许多简单计算)。内核通过等待“大量”数据待处理 - 或直到管道关闭来分摊成本,因为显然没有必要等待更多数据。这发生在每个进程对之间。您的bufsize=0
仅影响在父进程中写入,这就是为什么它仅用于为管道的第一阶段提供服务。
有些程序提供控制输出缓冲的选项(即,它们可以要求内核尽早传输数据):Python本身提供python -u
。 (如果它是您的 Python程序,请使用flush()
,例如每个进程中建议的gddc。)否则,有一个(大部分)通用实用程序unbuffer
这可能会让你立即做出回应。
答案 1 :(得分:0)
这是一个适合您的解决方案:
#!/usr/bin/python3
import sys, subprocess
length = 4
stdin = sys.stdin
stdout = subprocess.PIPE
command = ['python3', './cat.py']
for i in range(length):
if i == length - 1:
stdout = open('stdout', 'w')
stderr = open('{}.stderr'.format(i), 'w')
process = subprocess.Popen(command, stdin=stdin, stdout=stdout, stderr=stderr)
stdin = process.stdout
process.communicate()
'./cat.py'
对我不起作用,我必须使用['python3', './cat.py']
stdout
到下一个stdin
stdout
为subprocess.PIPE
,除了最后一个,即文件communicate()
将设置管道链祝你有个美好的一天。