假设我有大量作业(数十个或数百个)需要执行,但它们是 CPU 密集型的,并且只能同时运行几个作业。有没有一种简单的方法可以X
立即运行作业并在完成后开始新的作业?我唯一能想到的是如下(伪代码):
jobs=(...);
MAX_JOBS=4;
cur_jobs=0;
pids=(); # hash/associative array
while (jobs); do
while (cur_jobs < MAX_JOBS); do
pop and spawn job and store PID and anything else needed;
cur_jobs++;
done
sleep 5;
for each PID:
if no longer active; then
remove PID;
cur_jobs--;
done
我觉得我的解决方案过于复杂,就像我经常做的那样。目标系统是 FreeBSD,如果可能有某个端口可以完成所有艰苦的工作,但通用解决方案或通用习惯用法会更好。
答案1
如果你有 GNU Parallel,你可以这样做:
parallel do_it {} --option foo < argumentlist
GNU Parallel 是一个通用并行器,可以轻松地在同一台计算机或多台您可以通过 ssh 访问的计算机上并行运行作业。
如果您想要在 4 个 CPU 上运行 32 个不同的作业,则并行化的直接方法是在每个 CPU 上运行 8 个作业:
相反,GNU Parallel 在完成后会生成一个新进程 - 保持 CPU 处于活动状态,从而节省时间:
安装
如果您的发行版未打包 GNU Parallel,您可以进行个人安装,不需要 root 访问权限。这样做可以在 10 秒内完成:
(wget -O - pi.dk/3 || curl pi.dk/3/ || fetch -o - http://pi.dk/3) | bash
对于其他安装选项,请参阅http://git.savannah.gnu.org/cgit/parallel.git/tree/README
了解更多
查看更多示例:http://www.gnu.org/software/parallel/man.html
观看介绍视频:https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1
浏览本教程:http://www.gnu.org/software/parallel/parallel_tutorial.html
注册电子邮件列表以获得支持:https://lists.gnu.org/mailman/listinfo/parallel
答案2
你可以,但它很棘手且脆弱。有多种选择,其中之一是xargs
.
这篇有趣的文章讨论了依赖作业控制和信号时遇到的问题,确实值得推荐阅读:
http://prll.sourceforge.net/shell_parallel.html
这个人显然制作了一个新工具prll
,可以并行执行任意 shell 函数(具有自动检测或用户定义的池大小),它使用同步所有输入和输出的控制进程。
答案3
我的情况与您完全相同,但我需要并行运行的作业是运行 ruby 脚本的命令。首先我需要承认它并不完美,相反,它很脆弱。
我在 ruby 代码中所做的是,
counting_process = IO.popen "ps -e | grep 'YourCMDPattern' -c"
count_of_processes = counting_process.readlines[0].to_i
然后在 while 循环中,我定期检查进程的计数,然后当计数低于我想要保留的并行执行数时,触发 shell 命令使用 ruby 的 IO.popen 运行一定数量的新进程。
请注意,我需要运行的 shell 命令是动态的,并且包含从 ruby 代码生成的变量,这就是为什么我必须在 ruby 脚本中执行此操作。
如果不涉及 ruby,GNU Parallel 似乎是一个更好的选择。