我想从 python 调用一个外部进程。我正在调用的进程读取输入字符串并给出标记化结果,然后等待另一个输入(如果有帮助,二进制是 MeCab 标记器)。
我需要通过调用这个过程来标记数千行字符串。
问题是Popen.communicate()工作,但在给出 STDOUT 结果之前等待进程终止。我不想继续关闭和打开新的子流程数千次。(而且我不想发送整个文本,将来它可能很容易增长到数万行。)
from subprocess import PIPE, Popen
with Popen("mecab -O wakati".split(), stdin=PIPE,
stdout=PIPE, stderr=PIPE, close_fds=False,
universal_newlines=True, bufsize=1) as proc:
output, errors = proc.communicate("foobarbaz")
print(output)
我尝试阅读proc.stdout.read()
而不是使用通信,但它被阻止并且在调用stdin
之前不返回任何结果。proc.stdin.close()
这又意味着我每次都需要创建一个新流程。
我尝试从下面类似的问题中实现队列和线程,但是它要么不返回任何内容,因此卡在上面While True
,要么当我通过重复发送字符串来强制 stdin 缓冲区填充时,它会立即输出所有结果。
from subprocess import PIPE, Popen
from threading import Thread
from queue import Queue, Empty
def enqueue_output(out, queue):
for line in iter(out.readline, b''):
queue.put(line)
out.close()
p = Popen('mecab -O wakati'.split(), stdout=PIPE, stdin=PIPE,
universal_newlines=True, bufsize=1, close_fds=False)
q = Queue()
t = Thread(target=enqueue_output, args=(p.stdout, q))
t.daemon = True
t.start()
p.stdin.write("foobarbaz")
while True:
try:
line = q.get_nowait()
except Empty:
pass
else:
print(line)
break
还查看了 Pexpect 路由,但它的 windows 端口不支持一些重要的模块(基于 pty 的模块),所以我也不能应用它。
我知道有很多类似的答案,我已经尝试了其中的大部分。但是我尝试过的任何东西似乎都无法在 Windows 上运行。
编辑:当我通过命令行使用它时,我正在使用的二进制文件的一些信息。它运行并标记我给出的句子,直到我完成并强行关闭程序。
(...waits_for_input -> input_recieved -> 输出 -> waits_for_input...)
谢谢。