根据 GNU Parallel 邮件列表,这不是 GNU Parallel 特有的问题。他们建议我在这里发布我的问题。
我收到的错误是“管道损坏”错误,但我觉得我应该先解释一下我的问题背景以及导致此错误的原因。在 GNU Parallel 中尝试使用任何包含“while read”循环的 bash 脚本时,就会发生这种情况。
我有一个像这样的基本 bash 脚本:
#!/bin/bash
# linkcheck.sh
while read domain
do
host "$domain"
done
假设我想要导入一个大列表(比如说 250mb)。
cat urllist | ./linkcheck.sh
在 250mb 大小的 URL 上运行 host 命令相当慢。为了加快速度,我想在管道传输之前将输入拆分成块,然后并行运行多个作业。GNU Parallel 可以做到这一点。
cat urllist | parallel --pipe -j0 parallel ./linkcheck.sh {}
{} 逐行替换为 urllist 的内容。假设我的系统默认设置能够在每个并行实例中运行 500 个作业。为了绕过这个限制,我们可以并行化 Parallel 本身:
cat urllist | parallel -j10 --pipe parallel -j0 ./linkcheck.sh {}
这将运行 5000 个作业。不幸的是,它还会导致错误“管道损坏”(bash 常见问题解答)。但是,如果我删除 while read 循环并直接从输入到 {} 的任何内容中获取输入,脚本就会开始工作,例如,
#!/bin/bash
# linkchecker.sh
domain="$1"
host "$1"
为什么它不能与 while read 循环一起使用?关闭 SIGPIPE 信号以停止“管道损坏”消息是否安全,或者是否会产生诸如数据损坏之类的副作用?
谢谢阅读。
答案1
那么,
cat urllist | parallel --pipe -j0 parallel ./linkcheck.sh {}
工作正常吗?我认为你的问题部分可能是你漏掉了第二个--pipe
,比如
cat urllist | parallel -j10 --pipe parallel -j0- 管道./linkcheck.sh {}
顺便说一句,你永远不需要说
猫一个文件|一些命令
您可以随时将其更改为
一些命令<一个文件
从而减少一个进程(并减少一个管道)。 (cat
当您有多个输入文件时,使用它可能是适当/必要的。)
答案2
在我看来,错误可能是由于竞争条件不良而引起的,因为在管道仍处于打开状态时,分叉子进程运行 linkcheck.sh 的另一个副本与子进程实际尝试读取之间的时间窗口。在该窗口中,另一个副本已读取 EOF 并且管道已关闭。