【问题标题】:Run several jobs parallelly and Efficiently并行高效地运行多个作业
【发布时间】:2014-03-06 08:45:06
【问题描述】:

操作系统:Cent-OS

我有一些30,000 工作(或脚本)要运行。每项工作需要 3-5 分钟。我有48 CPUs(nproc = 48)。我可以同时使用40 CPUs to run 40 Jobs。请建议一些脚本或工具通过并行运行每 40 个作业来处理 30,000 个作业。

我做了什么:

  • 我创建了 40 个不同的文件夹,并通过为每个目录创建一个 shell 脚本并行执行作业。

  • 我想知道下次处理这类工作的更好方法。

【问题讨论】:

  • 编写一个脚本,其任务是通过分叉最多 40 个进程来分发 30,000 个作业。这个父脚本将等待子进程完成并通过分叉一个新进程继续下一个作业。在任何时候,您最多可以有 40 个子进程。
  • 您现在有 40 个文件夹保存“文件?”每个工作,对吧?为什么不使用一个名为“queue/”的文件夹来保存所有文件,而运行作业的脚本将“将一个文件从文件夹 queue/ 移动到文件夹 working/ 并处理该作业;完成后移动文件到文件夹完成/“?这样你启动的脚本数=并发数;您可以查看队列中的内容、工作中的内容和已完成的内容。当您需要重新开始时,只需将所有文件移回“queue/”文件夹即可。您还可以在其仍在处理过程中添加更多作业或删除尚未开始的作业。
  • 注意:在您的作业处理脚本中,当它“移动”文件时,最好将其移动到文件夹“working/”,并在文件名中附加其 pid ($$),并检查移动的文件确实持有它的pid(在文件名中)。这是一种处理锁定的简单方法,因为文件系统将以原子方式“移动”文件,不需要信号量或锁定。
  • @KenCheung forking 需要执行您的建议。
  • 哦...是的。事实上,我有类似的东西,我的脚本开始使用 /etc/inittab (CentOS 5),当 queue/ 文件夹中没有文件时它会休眠。

标签: linux parallel-processing


【解决方案1】:

正如 Mark Setchell 所说:GNU Parallel。

find scripts/ -type f | parallel

如果你坚持让 8 个 CPU 空闲:

find scripts/ -type f | parallel -j-8

但通常使用nice 会更有效,因为这样可以在没有其他人需要的情况下为您提供全部 48 个内核:

find scripts/ -type f | nice -n 15 parallel

要了解更多信息:

【讨论】:

  • 但是它会只提供 48 个工作还是会提交所有 30K 个工作?
  • 它将为每个 cpu 核心运行 1 个作业,直到完成所有 30K 个作业。如果您有更多问题,我建议您先观看介绍视频并浏览教程:它将解决大多数问题。
【解决方案2】:

我使用REDIS 来做这种事情——安装非常简单,CLI 也很容易使用。

我主要使用 LPUSH 将所有作业推送到 REDIS 中的“队列”中,并使用 BLPOP 从队列中阻塞删除作业。因此,您将在开始时 LPUSH 30,000 个作业(或脚本名称或参数),然后在后台启动 40 个进程(每个 CPU 1 个),每个进程将坐在循环中执行 BLPOP 以获取作业,运行它然后做下一个。

您可以添加复杂的层以在另一个“队列”中记录已完成的作业。

这里有一个小例子来说明该怎么做......

首先,在网络中的任何机器上启动 Redis 服务器:

./redis-server &    # start REDIS server in background

或者,如果你总是使用它,你可以把它放在你的系统启动中。

现在将 3 个作业推送到名为作业的队列中:

./redis-cli         # start REDIS command line interface
redis 127.0.0.1:6379> lpush jobs "job1"
(integer) 1
redis 127.0.0.1:6379> lpush jobs "job2"
(integer) 2
redis 127.0.0.1:6379> lpush jobs "job3"
(integer) 3

查看队列中有多少作业:

redis 127.0.0.1:6379> llen jobs
(integer) 3

等待作业无限超时

redis 127.0.0.1:6379> brpop jobs 0
1) "jobs"
2) "job1"
redis 127.0.0.1:6379> brpop jobs 0
1) "jobs"
2) "job2"
redis 127.0.0.1:6379> brpop jobs 0
1) "jobs"
2) "job3"

最后一个将等待很长时间,因为队列中没有作业:

redis 127.0.0.1:6379> brpop jobs 0

当然,这很容易编写脚本:

将 30,000 个作业放入队列中:

for ((i=0;i<30000;i++)) ; do
    echo "lpush jobs job$i" | redis-cli
done

如果您的 Redis 服务器位于远程主机上,只需使用:

redis-cli -h <HOSTNAME>

查看进度的方法如下:

echo "llen jobs" | redis-cli
(integer) 30000

或者,更简单地说:

redis-cli llen jobs
(integer) 30000

你可以像这样开始 40 个工作:

#!/bin/bash
for ((i=0;i<40;i++)) ; do
    ./Keep1ProcessorBusy  $i &
done

然后Keep1ProcessorBusy 会是这样的:

#!/bin/bash

# Endless loop picking up jobs and processing them
while :
do
    job=$(echo brpop jobs 0 | redis_cli)
    # Set processor affinity here too if you want to force it, use $1 parameter we were called with
    do $job
done

当然,您想要运行的实际脚本或作业也可以存储在 Redis 中。


作为一个完全不同的选项,您可以查看GNU Parallel,即here。另外请记住,您可以使用-P 选项运行findxargs 的输出以并行化内容。

【讨论】:

  • 任何关于 Redis 的教程都会对这项工作很有帮助。
  • 我已经用一个非常具体的例子更新了我的答案,它可以帮助你了解它是多么简单。
  • +1 向我展示了各种选项。我正在使用并行工作。感谢您的帮助。
【解决方案3】:

只需执行这些脚本,Linux 就会在内部将这些任务正确地分配给可用的 CPU。这是基于 Linux 任务调度程序的。但是,如果您愿意,您也可以使用 taskset 在特定 CPU 上执行任务(请参阅 man taskset)。您可以通过脚本来执行 30K 任务。以这种手动方式记住,确保你在做什么。

【讨论】:

  • 我认为这个问题暗示他不希望所有 30K 作业同时运行。使用任务集分配处理器亲和性并不意味着作业将一一执行。它们将像我们在 Linux 上只有一个 CPU(内核)的那一天一样一起运行 - 多任务处理。
  • taskset 将特定任务仿射到特定 CPU,我的意思是将所有这些任务仿射到可用 CPU 并以循环方式安排它们,我也警告过他。我只是告诉他他的可用选项,我没有坚持。
  • 我看不出这对这份工作有什么用处。
  • @aravindramesh 你没听懂。
  • 让我试一试,每当您运行脚本时,它都是一个新进程。 Linux任务调度器负责决定你的任务将如何获得cpu,即哪个任务将获得它在任务调度器上的哪个CPU,调度器还包含负载均衡器,它确保没有CPU保持空闲,每当CPU空闲时,它就会从中拉出任务其他繁忙的 CPU,这样 Linux 可以提供最佳吞吐量。把它们全部运行。现在,如果你想一次将它们分成 40 个任务,你可以这样做,但不是严格要求。但是,如果你真的想要它,那么你可以借助任务集。希望你得到它
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-25
  • 2023-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多