proc = subprocess.Popen(['start'],stdin=subprocess.PIPE,stdout=subprocess.PIPE)
proc.stdin.write('issue commands')
proc.stdin.write('issue more commands')
output = proc.stdout.read() # Deadlocked here
# Actually I have more commands to issue here
我知道communication()可以为我提供这个问题的解决方案,但我想稍后发出更多命令。但是communication()有点关闭子进程。
这里有什么知道的工作吗?我正在尝试使用python包装器与路由器进行交互。所以我有更多的命令出现,也可以产生一些输出。在那种情况下,如何在不终止子进程的情况下进行读取。
答案 0 :(得分:10)
output = proc.stdout.read() # Deadlocked here
该行导致死锁,因为read()
在读取EOF之前不会返回,EOF在另一方关闭其stdout时发送(例如,当子进程终止时)。相反,您想要读取面向行的输入:
output = proc.stdout.readline()
在读取换行符(或EOF)后,即在readline()
读取行之后, readline()
将返回。
您的下一次死锁将来自:
当子进程尝试读取面向行的输入时,不会向发送到子进程的输出添加newline
,即子进程在从stdin读取时查找换行符。
输出不是flushing
,这意味着对方永远不会看到任何要读取的数据,因此另一方会挂起等待数据。
为了提高效率,当你写入一个文件(包括stdout,stdin)输出缓冲时,这意味着python不是将输出实际写入文件,而是将输出存储在列表(称为缓冲区)。然后当列表增长到一定大小时,python会立即将所有输出写入文件,这比一次写一行更有效。
不能为发送到子流程的所有输出添加换行符,可以很容易地更正;但是,发现所有需要刷新缓冲区的地方更加困难。这是一个例子:
prog.py:
#!/usr/bin/env python3.4 -u
import sys
print('What is your name?')
name = input()
print(name)
print("What is your number?")
number = input()
print(number)
假设您想用其他程序驱动该程序?
制作prog.py
可执行文件:$ chmod a+x prog.py
注意shebang线。
请注意shebang行中python解释器的-u flag
,这意味着的所有输出程序都将是无缓冲的,即它将直接写入{{ 1}} - 没有累积在缓冲区中。
stdout
对评论的回应:
你可能遭受缓冲。大多数程序缓冲输出以提高效率此外,一些程序将尝试确定它们的stdout是否连接到终端 - 如果是,则程序使用行缓冲,这意味着从缓冲区检索输出并实际写入stdout每次程序输出换行符。这允许使用连接终端的人与程序进行交互。
另一方面,如果程序的stdout没有连接到终端,程序将阻塞缓冲区,这意味着从缓冲区中检索输出,并且只有在缓冲区有缓冲区之后才会将其写入stdout增长到特定大小,比如4K数据。如果程序是块缓冲并且输出小于4K,则实际上没有任何内容写入stdout。块缓冲允许其他计算机程序以更高的效率检索程序的输出。
如果路由器程序是块缓冲,并且输出的块大小小于块大小,那么实际上没有任何内容写入stdout,因此你的python程序没有任何东西可以读取。
您的python程序不是终端,因此路由器程序可能是块缓冲。正如JF Sebastian在评论中指出的那样,有办法欺骗路由器程序认为你的python程序是一个终端,这会导致路由器程序行缓冲区,因此你将能够用import subprocess as sp
child = sp.Popen(
['./prog.py'],
stdin = sp.PIPE,
stdout = sp.PIPE
)
print_question = child.stdout.readline().decode('utf-8') #PIPE's send a bytes type,
#so convert to str type
name = input(print_question)
name = "{}\n".format(name)
child.stdin.write(
name.encode('utf-8') #convert to bytes type
)
child.stdin.flush()
print_name = child.stdout.readline().decode('utf-8')
print("From client: {}".format(name))
print_question = child.stdout.readline().decode('utf-8')
number = input(print_question)
number = "{}\n".format(number)
child.stdin.write(
number.encode('utf-8')
)
child.stdin.flush()
print_number = child.stdout.readline().decode('utf-8')
print("From client: {}".format(print_number))
从stdout读取。看看pexpect。