我需要通过调用此进程来对数千行字符串进行标记化处理。
问题在于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上似乎没有任何我尝试过的方法可以工作。
编辑:关于我使用的二进制文件的一些信息,当我通过命令行使用它时。它会运行并标记我给出的句子,直到我完成并强制关闭程序。
(...等待输入 -> 输入接收 -> 输出 -> 等待输入...)
谢谢。
FILE
流,则管道stdout
具有4 KiB缓冲区。您是否尝试过重复写入输入,直到mecab填充并刷新其stdout
缓冲区?mecab是否有命令行选项来强制使用无缓冲或行缓冲而不是完全缓冲? - Eryk SunFILE
流使用的输出缓冲区大小。C运行时情况太复杂了。一个进程可以静态或动态地链接到一个或多个CRT。Linux上的情况不同,因此有像stdbuf
这样的命令可以尝试修改标准FILE
流的缓冲。 - Eryk Sun