【发布时间】:2020-08-04 05:02:04
【问题描述】:
我正在从 Python 3.7.3 调用带有子进程的 Perl 脚本。调用的 Perl 脚本是这个:
https://github.com/moses-smt/mosesdecoder/blob/master/scripts/tokenizer/tokenizer.perl
我用来调用它的代码是:
import sys
import os
import subprocess
import threading
def copy_out(source, dest):
for line in source:
dest.write(line)
num_threads=4
args = ["perl", "tokenizer.perl",
"-l", "en",
"-threads", str(num_threads)
]
with open(os.devnull, "wb") as devnull:
tokenizer = subprocess.Popen(args,
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=devnull)
tokenizer_thread = threading.Thread(target=copy_out, args=(tokenizer.stdout, open("outfile", "wb")))
tokenizer_thread.start()
num_lines = 100000
for _ in range(num_lines):
tokenizer.stdin.write(b'Random line.\n')
tokenizer.stdin.close()
tokenizer_thread.join()
tokenizer.wait()
在我的系统上,这会导致以下错误:
Traceback (most recent call last):
File "t.py", line 27, in <module>
tokenizer.stdin.write(b'Random line.\n')
BrokenPipeError: [Errno 32] Broken pipe
我对此进行了调查,结果发现如果子进程的 -threads 参数为 1,则不会引发错误。由于我不想放弃子进程中的多线程,所以我的问题是:
首先是什么导致了这个错误? “谁”应该为此负责:操作系统/环境、我的 Python 代码、Perl 代码?
如果需要,我很乐意提供更多信息。
编辑:回应一些cmets,
- 只有当你也有这个文件时才能运行 Perl 脚本:https://github.com/moses-smt/mosesdecoder/blob/master/scripts/share/nonbreaking_prefixes/nonbreaking_prefix.en
- Perl 脚本实际上在处理失败之前处理了数千行。在我上面的 Python 脚本中,如果我将
num_lines变小,我不会再收到此错误。 - 如果我只是在命令行上调用这个 Perl 脚本,而不使用任何 Python,它可以正常工作:
无论有多少 (Perl) 线程或输入行。 - 我的Python变量
num_threads只控制Perl子进程的线程数。我从不启动多个 Python 线程,只启动一个。
编辑 2:在我的第一次编辑中,我错误地指出这个 Perl 程序在调用时运行良好,例如来自命令行的-threads 4:在那里,使用了不同的 Perl,它是用多线程编译的。如果我使用从 Python 调用的相同 Perl,我会得到:
$ cat [file with 100000 lines] | [correct perl] tokenizer.perl -l en -threads 4
Can't locate object method "new" via package "Thread" at
tokenizer.perl line 130, <STDIN> line 8000.
这无疑会帮助我更好地调试它。
【问题讨论】:
-
Broken pipe 意味着 Perl 进程关闭了 Python 进程试图读取的输出流。需要查看 Perl 脚本才能进一步诊断。
-
@mob 感谢您的评论!我确实链接到了这个 Perl 脚本:github.com/moses-smt/mosesdecoder/blob/master/scripts/tokenizer/…
-
您是否检查过
load_prefixes()子在输入循环开始之前没有死?好像引用了一个$prefixfile变量,哪个文件可能不存在? -
@HåkonHægland 您好,感谢您的提示!这个文件肯定存在,因为 Perl 进程不会立即失败:它在失败之前确实处理了数千行。
-
@MathiasMüller 您是如何安装该文件的?如果我能得到它,我可以测试更多..
标签: python multithreading perl subprocess