gpt4 book ai didi

python - 如果作为 Python 子进程调用,多线程 Perl 脚本会导致管道损坏

转载 作者:行者123 更新时间:2023-12-01 23:23:22 25 4
gpt4 key购买 nike

我正在使用子进程从 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 代码?

如果需要,我很高兴提供更多信息。


编辑:要回复一些评论,

  • 只有当您还有此文件时才能运行 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.

这无疑会帮助我更好地调试它。

最佳答案

问题似乎是如果 perl 不支持线程,perl 脚本就会崩溃。您可以通过运行以下命令来检查您的 perl 是否支持线程:

perl -MConfig -E 'say "Threads supported" if $Config{useithreads}'

就我而言,输出为空,因此我安装了一个具有线程支持的新 Perl:

perlbrew install perl-5.30.0 --as=5.30.0-threads -Dusethreads
perlbrew use 5.30.0-threads

然后我再次运行Python脚本:

import sys
import os
import subprocess
import threading

def copy_out(source, dest):
for line in iter(source.readline, b''):
dest.write(line)

num_threads=4
args = ["perl", "tokenizer.perl",
"-l", "en",
"-threads", str(num_threads)
]
tokenizer = subprocess.Popen(
args,
bufsize=-1, #use default bufsize = 8192 bytes
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.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()

现在它运行到最后,没有错误,并生成了包含 100000 行的输出文件 outfile

关于python - 如果作为 Python 子进程调用,多线程 Perl 脚本会导致管道损坏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61343709/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com