1

我希望能够运行一系列命令,而无需事先知道具体有多少和哪些。这些命令通常是一些计算,每个计算需要几个小时/几天。我需要一些方法来修改后验命令列表,因为它在集群上运行,我需要提前保留节点。

我希望它(无论是什么)(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 {}'

笔记

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

我试过的

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

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

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

为了避免 EOF 问题,我想我可以用 tail 跟随流

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

这非常接近,我可以添加命令并且它不会关闭文件。但是,它永远不会结束,并且在读取“退出”时不会停止,而是挂起。我不确定为什么。也许它正在读取块。(??)此外,如果所有进程都已完成并且文件中没有任何事情可做,它不会停止。

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

或者,我可以想象一些事情,为每个 CPU 启动一些带有“等待 PID”的子进程,但它看起来过于复杂,而且这似乎正是 GNU/parallel 应该做的事情。

感谢您的任何帮助或建议!


根据此处 的评论进行编辑,这至少会退出,但它首先需要关键字“退出”。

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

正如该线程中所建议的,也可以使用“xargs -P2”而不是“parallel -j2”,但这并不能解决问题。

4

3 回答 3

2

对于您的问题来说,这可能有点矫枉过正,但您可以使用Bosco

它的作用是从集群请求一些资源(支持许多作业调度程序),然后您的笔记本电脑上运行了一个本地队列系统,因此您可以在本地提交作业,它们将“融入”集群上的分配中。

您可以向本地 Bosco 安装提交任意数量的任务,它会考虑在集群上实际运行它们,同时考虑到分配的 CPU 数量。

如果您忘记了一项任务,您只需再提交一项到您当地的 Bosco 安装,它就会处理它。

于 2014-08-05T20:00:12.600 回答
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,让tail我们明白我们已经完成了。

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

于 2014-08-05T23:21:02.207 回答
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
于 2014-08-05T18:22:35.987 回答