我在 GitHub 上找到了一个脚本,我对其进行了轻微修改,以满足我尝试在队列中运行的程序的需求。
但是它不起作用,我不知道为什么。它实际上从未将作业回显到队列文件。
以下是 GitHub 页面的链接:
https://gist.github.com/tubaterry/c6ef393a39cfbc82e13b8716c60f7824
这是我修改的版本:
#!/bin/sh
END="END"
true > queue
tail -n+0 -f queue | parallel -j 16 -E "$END"
while read i; do
echo "command [args] > ${i%.inp}.log 2> ${i%.inp}.err" > queue
done < "jobs.txt"
echo "$END" >> queue
echo "Waiting for jobs to complete"
while [ "$(pgrep 'perl /usr/local/bin/parallel' | grep -evc 'grep' | tr -d " ")" -gt "0" ]; do
sleep 1
done
touch killtail
mv killtail queue
rm queue
我唯一能想到的是,其中一个步骤在 OpenBSD 上没有按预期运行。但我重新安排了一个步骤,一切都执行没有错误,但它只提交了一项作业。更改是tail -n+0 -f queue | parallel -j 16 -E "$END"
在第一个 while 循环之后移动并更改true > queue
为,touch queue
因为我不太确定true > queue
意味着什么。
任何帮助,将不胜感激。
编辑:
我有一个 jobs.txt 文件,其中填充了我计划运行的命令的输入文件的路径。 jobs.txt 中的文件将是命令的参数之一,然后我将计算结果输出到日志文件,并将任何错误输出到错误文件。
我的期望是,每个作业将被添加到队列中,并且并行将执行最多 16 个作业,每个核心一个,因为命令的参数之一是每次计算一个核心的利用率。这将继续,直到到达由并行的 -E 参数表示的“END”。
正如所写,jobs.txt 没有任何回显到队列。我会再试一次 >>
我对原剧本中的很多内容提出了质疑。我改变了我确定的事情,但有些功能我感到非常困惑,并决定保持原样。
我不清楚的事情之一是 tail -n+0
我不知道那是做什么的
编辑2:
${PROGRAM} ${JOB}.inp ${NCPU} > ${JOB}.log 2> ${JOB}.err
${JOB} 是对 1 到 ∞ 计算之间任意位置的引用,具体取决于我在给定时间需要执行的操作数量。目前,jobs.txt 有 374 个我需要运行的单独测试。 ${PROGRAM} 是从 ${JOB}.inp 获取参数并进行相应计算的软件。 ${NCPU} 是每个作业要使用的核心数量;目前我正在尝试在 16 核处理器上串行运行每个作业。
目标是根据需要对尽可能多的计算进行排队,而无需输入完整的命令。我只想使用生成一个列表find calculations -name '*.inp' -print > jobs.txt
,然后运行一个脚本(例如 SerialRun.sh 或 ParallelRun.sh)并让它生成结果。这些作业可能会嵌套在许多不同的目录中,具体取决于不同用户选择如何组织其工作,并且使用 find 的这种方法允许我非常快速地提交作业并将结果生成到正确的路径。每次计算完成后,我可以在系统继续运行测试的同时分析数据。
该脚本很可能过于复杂。我一直在寻找一个作业队列系统,并找到了 nqs,它成为了 GNU Parallel 项目。我找不到很多并行队列作业的示例,但在 GitHub 上发现了该脚本,并决定尝试一下。我对它的编写方式有很多疑问,但我对并行的理解还不足以质疑它。
我认为为它建立一个队列应该比这更简单一些。
编辑3:
也许正确的方法是这样做:
while read i; do
command "$i" > "${i%.inp}".log 2> "${i%.inp}".err | parallel -j 16
done < "jobs.txt"
那行得通吗?
答案1
你不需要这个复杂的脚本,parallel
可以自己做你想做的事情。只需.inp
使用您选择的任何其他工具从文件列表中删除扩展名sed
,然后输入基本名称,如下parallel
所示:
sed 's/\.inp//' jobs.txt | parallel -j 16 "${PROGRAM} {}.inp > {}.log 2> {}.err"
该{}
符号是并行基本功能的一部分,描述man parallel
如下:
{} 输入行。
该替换字符串将被从输入源读取的整行替换。输入源通常是 stdin(标准输入),但也可以用
--arg-file
、:::
或给出::::
。
因此,它只是被您传递给并行的任何内容替换,在本例中是文件名列表,其扩展名被sed
.
或者,您可以使用{.}
以下内容:
{.} 不带扩展名的输入行。
此替换字符串将被删除扩展名的输入替换。如果输入行包含 .最后一个 / 之后,最后一个 .直到字符串的末尾将被删除,并且 {.} 将被剩余的部分替换。例如 foo.jpg 变为 foo,subdir/foo.jpg 变为 subdir/foo,sub.dir/foo.jpg 变为 sub.dir/foo,sub.dir/bar 仍为 sub.dir/bar。如果输入行不包含 .它将保持不变。
替换字符串 {.} 可以使用 --extensionreplace 更改
有了这个,您甚至不需要该jobs.txt
文件。如果所有文件都位于同一目录中,您可以执行以下操作:
parallel -j 16 "${PROGRAM} {.}.inp > {.}.log 2> {.}.err" ::: *.inp
或者,要使其递归地下降到子目录,假设您正在使用bash
,您可以执行以下操作:
shopt -s globstar
parallel -j 16 "${PROGRAM} {.}.inp > {.}.log 2> {.}.err" ::: **/*.inp