在不破坏管道的情况下与进程多次通信?

Posted

技术标签:

【中文标题】在不破坏管道的情况下与进程多次通信?【英文标题】:Communicate multiple times with a process without breaking the pipe? 【发布时间】:2011-03-05 03:36:54 【问题描述】:

这不是我第一次遇到这个问题,而且真的很困扰我。 每当我使用 Python subprocess 模块打开管道时,我只能使用它一次 communicate,如文档所述:Read data from stdout and stderr, until end-of-file is reached

proc = sub.Popen("psql -h darwin -d main_db".split(),stdin=sub.PIPE,stdout=sub.PIPE)
print proc.communicate("select a,b,result from experiment_1412;\n")[0]
print proc.communicate("select theta,zeta,result from experiment_2099\n")[0]

这里的问题是第二次,Python 不高兴。的确,他决定在第一次沟通后关闭文件:

Traceback (most recent call last):
File "a.py", line 30, in <module>
    print proc.communicate("select theta,zeta,result from experiment_2099\n")[0]
File "/usr/lib64/python2.5/subprocess.py", line 667, in communicate
    return self._communicate(input)
File "/usr/lib64/python2.5/subprocess.py", line 1124, in _communicate
     self.stdin.flush()
ValueError: I/O operation on closed file

是否允许多次通信?

【问题讨论】:

对于 psql,有很多现有的 Python 包装器:wiki.python.org/moin/PostgreSQL 【参考方案1】:

您只需调用communicate()就可以做到这一点:

query1 = 'select a,b,result from experiment_1412;'
query1 = 'select theta,zeta,result from experiment_2099;'
concat_query = "\n".format(query1, query2)
print(proc.communicate(input=concat_query.encode('utf-8'))[0])

这里的关键是你只给stdin写一次,\n作为EOL。 您的 psql 子进程从stdin 读取直到\n,然后在完成第一个查询后,它再次转到stdin,此时缓冲区中只剩下第二个查询字符串。

【讨论】:

这会在内存中缓冲整个输入,使得该解决方案对于需要流式 I/O 的情况不太理想。【参考方案2】:

你可以使用:

proc.stdin.write('input')    
if proc.stdout.closed:
    print(proc.stdout)

【讨论】:

【参考方案3】:

我认为你误解了沟通......

http://docs.python.org/library/subprocess.html#subprocess.Popen.communicate

communicate 向另一个进程发送一个字符串,然后等待它完成......(就像你说的等待 EOF 监听标准输出和标准错误)

你应该做的是:

proc.stdin.write('message')

# ...figure out how long or why you need to wait...

proc.stdin.write('message2')

(如果您需要获取 stdout 或 stderr,您可以使用 proc.stdout 或 proc.stderr)

【讨论】:

我意识到你可能想看看@***.com/questions/375427/…(这是一个非常相似的问题) 确实,我需要非阻塞读取,因为写入可能总是取决于读取的内容。 来自subprocess documentation 的警告: > 警告:使用communicate() 而不是.stdin.write.stdout.read.stderr.read 以避免由于任何其他操作系统管道缓冲区填满而导致的死锁和阻塞子进程。【参考方案4】:

我以前遇到过这个问题,据我所知,subprocess 无法做到这一点(我同意,如果这是真的,那是非常违反直觉的)。我最终使用了pexpect(可从 PyPI 获得)。

【讨论】:

以上是关于在不破坏管道的情况下与进程多次通信?的主要内容,如果未能解决你的问题,请参考以下文章

我想知道如何在不通过 chrome 打印弹出窗口的情况下与网络中的打印机进行通信

Windows进程间通信—命名管道

命名管道

Linux进程间通信 -- 使用命名管道

进程间通信的方式

进程间通信:命名管道