运行 - 最初未知 - 并行的bash命令数

时间:2014-08-05 16:42:22

标签: bash parallel-processing tail gnu-parallel

我希望能够在不事先知道确切数量和确切数量的情况下运行一系列命令。这些命令通常是一些计算,每个计算需要几个小时/天。我需要一些方法来修改命令列表 a posteriori ,因为它在集群上运行,我需要提前保留节点。

我希望它(无论是什么)来(i)在运行时读取命令并在处理器释放时继续启动它们,以及(ii)在没有更多命令运行时退出。

实现这一目标的最简单方法是什么?

编辑:这有效(与GNU并行)

首先,根据答案中的建议,修改parallel(例如/usr/bin/parallel),更改

# Ignore the rest of input file
while (<$fh>) {}

# Ignore the rest of input file
close $fh; 

然后像这样测试:

seq 10 > test;   tail -f test | parallel -uE EXIT 'echo {}'

注意

  • &#34; -u&#34;用于&#34; ungroup&#34;这样所有的行都会在它们到来时被读取,执行和打印,并且可以使用过程
  • &#34; -E EXIT&#34;是这样我们可以杀死:在写EXIT之后必须写另一个(任意的)字符串,以便&#39; tail -f&#39;会死。 (如果不进行上述并行修改,将保持流打开,这将不起作用)
  • 如果流为空并且cpus空闲,它将不会退出:我认为这是一个更复杂的问题,也涉及同步,尽管可以通过类似if(items_processed>0 && nprocs_running==0) exit的方式完成。然后仍然存在杀死尾巴的问题,但是这可能会以一种丑陋的方式通过定期向输入文件写一些虚假来破解。

我尝试过的内容

我能想到的最简单的语法就是这样,使用GNU parallel:

parallel < command-list.txt
[...some time later...]
echo "this-command-I-forgot" >> command-list.txt

这很有效...除非,如果命令数小于CPU数(这是常见的,我可能从16-cpu机器上的10个进程开始)它将遇到EOF,关闭流我看不到添加更多命令的方法。因此,只要那些运行命令结束,它就会完成。

为了避免EOF问题,我想我可以跟踪尾巴

tail -n+0 -f command-list.txt | parallel --eof=EXIT

例如,在这个简单的测试中:

seq 10 > command-list.txt
tail -n+0 -f command-list.txt | parallel -j2 --eof=EXIT 'sleep 1 && echo {}'
echo "this-command-I-forgot" >> command-list.txt

这非常接近,我可以添加命令,但它不会关闭文件。 然而,它永远不会走到尽头,并且在阅读&#39; EXIT&#39;但是却挂起了。我不知道为什么。也许它是用块读取的。(??) 此外,如果所有流程都已完成,它将不会停止文件中没有任何内容可做。

编辑这可能与答案中提出的错误相关)

或者我可以想象一下,为每个CPU启动一些子进程并等待PID&#39;但它似乎过于复杂,而且这似乎是GNU / parallel应该做的事情。

感谢您提供任何帮助或建议!


修改 根据评论here,这至少会退出,但它需要关键字“退出”&#39;首先是在那里。

sh -c 'tail -n+0 -f command-list.txt | { sed "/EXIT/Q" && kill -9 $$ ;}' | parallel -j2  'sleep 1 && echo {}'

根据this thread的建议,也可以使用&#39; xargs -P2&#39;而不是&#39; parallel -j2&#39;虽然这并没有解决问题。

3 个答案:

答案 0 :(得分:2)

对于您的问题可能有点过分,但您可以使用Bosco

它的作用是从群集中请求一些资源(支持许多作业调度程序)然后您在笔记本电脑上运行本地队列系统,这样您就可以在本地提交作业,并且它们将“接入”在簇。

您可以根据需要向本地Bosco安装提交任意数量的任务,并且考虑到已分配的CPU数量,它将负责在群集上实际运行它们。

如果您忘记了一项任务,您只需再向当地的Bosco安装提交一项任务,它将负责处理。

答案 1 :(得分:1)

#!/bin/bash

exec 4< <(exec tail -n+0 -f command-list.txt)
TAIL_PID=$!
exec 5> >(exec parallel -j2 'sleep 1 && echo {}')

while IFS= read -ru 4 __; do
    if [[ $__ == EXIT ]]; then
        exec 4<&- 5>&-
        kill -s SIGHUP "$TAIL_PID"
        break
    fi
    echo "$__" >&5
done

答案 2 :(得分:1)

您似乎遇到了GNU parallel中可能存在的错误以及tail中可能存在的错误。

在GNU Parallel中更改以下内容:

        # Ignore the rest of input file                                                                   
        while (<$fh>) {}                                                                                 

为:

        # Ignore the rest of input file                                                                   
        close $fh;

然后使用:

tail -n+0 -f command-list.txt | (parallel -j2 --eof=EXIT {}; echo Parallel is now done; (seq 1000 >> command-list.txt &);echo Done appending dummy data)

完成:

echo pwd >> command-list.txt
echo "EXIT" >> command-list.txt

正如您所看到的那样parallel很好地结束了 - tail正悬空,但是seq完成后的最后parallel生成{{1}明白我们已经完成了。

tail在FreeBSD,OpenBSD和Debian GNU / Linux上具有相同的行为,因此虽然行为是次优的,但它可能不会被视为错误。