Python 如何在不使用communicate()的情况下避免子流程中的死锁
我知道communicate()可以给我一个解决这个问题的方法,但我想以后再发出更多的命令。但是communicate()关闭了子流程 这附近有专门的工作吗。我正在尝试使用python包装器与路由器交互。因此,我有更多的命令,也可以产生一些输出。在这种情况下,如何在不终止子进程的情况下进行读取Python 如何在不使用communicate()的情况下避免子流程中的死锁,python,subprocess,stdout,deadlock,popen,Python,Subprocess,Stdout,Deadlock,Popen,我知道communicate()可以给我一个解决这个问题的方法,但我想以后再发出更多的命令。但是communicate()关闭了子流程 这附近有专门的工作吗。我正在尝试使用python包装器与路由器交互。因此,我有更多的命令,也可以产生一些输出。在这种情况下,如何在不终止子进程的情况下进行读取 proc = subprocess.Popen(['start'],stdin=subprocess.PIPE,stdout=subprocess.PIPE) proc.stdin.write('issu
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
该行导致死锁,因为read()
在读取EOF之前不会返回,EOF是在另一方关闭其标准输出时发送的(例如,当子进程终止时)。相反,您希望读取面向行的输入:
output = proc.stdout.read() # Deadlocked here
readline()
将在读取换行符(或EOF)后返回,即readline()
读取一行后返回
您的下一个死锁将由以下任一原因导致:
output = proc.stdout.readline()
假设您想用另一个程序驱动该程序
prog.py
可执行:$chmod a+x prog.py
-u标志
,这意味着该程序的所有输出都将是无缓冲的,即它将直接写入stdout
——而不是累积在缓冲区中评论回复: 你可能正遭受缓冲的痛苦。大多数程序缓冲输出以提高效率。此外,一些程序将尝试确定其标准输出是否连接到终端——如果连接到终端,则程序采用行缓冲,这意味着每次程序输出换行时,从缓冲区检索输出并实际写入标准输出。这允许人类使用连接的终端与程序进行交互 另一方面,如果程序的stdout未连接到终端,则程序将阻塞缓冲区,这意味着只有在缓冲区增长到特定大小(例如4K数据)后,才会从缓冲区检索输出并实际写入stdout。如果程序是块缓冲的,并且输出小于4K,那么实际上不会向标准输出写入任何内容。块缓冲允许其他计算机程序以更高的效率检索程序的输出 如果路由器程序是块缓冲的,并且它的输出小于块大小,那么实际上没有任何内容写入标准输出,因此python程序没有任何内容可读取
python程序不是终端,因此路由器程序可能是块缓冲。正如J.F.Sebastian在评论中指出的,有一些方法可以欺骗路由器程序,使其认为您的python程序是一个终端,这将导致路由器程序使用行缓冲区,因此您可以使用
readline()
从其标准输出读取。查看pexpect。代码非常简单。请提供更多关于输入/输出的信息以及问题的具体内容。请阅读使用线程从stdout和stderr读取行,然后将它们放在主线程可以查看数据的队列中。只需在阅读之前添加proc.stdin.flush()
,一切都会好起来的。感谢所有人的帮助,它工作得很好。你知道如何避免被阻止吗?您使用了什么解决方案?它非常脆弱(您必须知道要准确读取多少数据——输入/输出可能很容易失去同步,从而导致死锁),并且它无法处理发生死锁时的情况。您可以异步使用或/写入管道。我也尝试过使用.readline()
,但没有任何运气。它也在等待一些东西,我已经在路由器中发出了打印命令,它在无休止的等待中。“请帮我解决这个问题。”JAugust,我的回答在我答案的底部。难道这不是一个非阻塞阅读吗?就像我读的一样,没有什么可读的,就让脚本继续吧,或者什么的?非常好的答案!非常感谢你!
#!/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)
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))