并行运行 shell 脚本
- 2024-11-13 08:36:00
- admin 原创
- 22
问题描述:
我有一个 shell 脚本
随机排列一个大型文本文件(600 万行和 6 列)
根据第一列对文件进行排序
输出 1000 个文件
伪代码如下
file1.sh
#!/bin/bash
for i in $(seq 1 1000)
do
Generating random numbers here , sorting and outputting to file$i.txt
done
有没有办法运行这个 shell 脚本parallel
来充分利用多核 CPU?
目前,./file1.sh
按顺序执行 1 到 1000 次,速度非常慢。
感谢您的帮助。
解决方案 1:
另一个非常方便的方法是使用gnu parallel,如果您还没有安装它,那么非常值得安装;如果任务不一定花费相同的时间,那么它是无价的。
seq 1000 | parallel -j 8 --workdir $PWD ./myrun {}
将启动./myrun 1
、./myrun 2
等,确保一次运行 8 个作业。如果您想同时在多个节点上运行,例如在 PBS 作业中,它还可以获取节点列表;我们为用户提供的有关如何在我们的系统上执行此操作的说明在此处。
更新以添加:您要确保您使用的是 gnu-parallel,而不是 moreutils 包中同名且功能更有限的实用程序(此处描述了两者的不同历史。)
解决方案 2:
检查bash 子 shell,它们可用于并行运行脚本的各个部分。
我还没有测试过这个,但这可能是一个开始:
#!/bin/bash
for i in $(seq 1 1000)
do
( Generating random numbers here , sorting and outputting to file$i.txt ) &
if (( $i % 10 == 0 )); then wait; fi # Limit to 10 concurrent subshells.
done
wait
解决方案 3:
要使并行运行,您可以在 shell 命令末尾使用“&”在后台运行它,然后wait
默认(即不带参数)等待所有后台进程完成。因此,也许可以并行启动 10 个,然后等待,然后再执行另外 10 个。您可以使用两个嵌套循环轻松完成此操作。
解决方案 4:
GNU parallel 文档中列出了一系列可以从 shell 并行运行作业的程序,甚至还对它们进行了比较。目前有很多解决方案。另一个好消息是,它们在调度作业方面可能非常高效,因此所有核心/处理器始终保持忙碌状态。
解决方案 5:
有一个简单的、可移植的程序可以为您完成这项工作:PPSS。PPSS会检查有多少个核心可用,并在每个任务完成后启动另一个任务,从而自动为您安排任务。
解决方案 6:
虽然以前的答案确实有效,但在我看来它们很难记住(当然 GNU 除外parallel
)。
我有点偏爱与上述类似的方法(( $i % 10 == 0 )) && wait
。我也见过这样的写法((i=i%N)); ((i++==0)) && wait
其中:
N
定义为您想要并行运行的作业数,并且i
是当前作业。
虽然上述方法有效,但其收益递减,因为您必须等待所有进程退出后才能让一组新进程开始工作,这会浪费任何具有任何执行时间的任务(即每个任务)的 CPU 时间。换句话说,在使用前面描述的方法开始新任务之前,并行任务的数量必须达到 0。
对我来说,这个问题在执行执行时间不一致的任务时变得明显(例如,执行从数据库中清除用户信息的请求 - 请求者可能存在也可能不存在,如果存在,则与不同请求者相关的记录可能会有数量级的差异)。我注意到一些请求会立即得到满足,而其他请求则会排队等待一个运行时间稍长的任务成功完成。这意味着一项任务需要数小时/数天才能完成,而之前定义的方法只需要几十分钟。
我认为下面的方法是在没有 GNU 的系统parallel
(例如 vanilla macOS)上维持恒定任务加载的更好的解决方案,并且希望比上面的字母汤更容易记住:
WORKER_LIMIT=6 # or whatever - remember to not bog down your system
while read -r LINE; do # this could be any kind of loop
# there's probably a more elegant approach to getting the number of background processes.
BACKGROUND_PROCESSES="$(jobs -r | wc -l | tr -d ' ')"
if [[ $BACKGROUND_PROCESSES -eq $WORKER_LIMIT ]]; then
# wait for 1 job to finish before starting a new one
wait -n
fi
# run something in a background shell
python example.py -item "$LINE" &
done < something.list
# wait for all background jobs to finish
wait
解决方案 7:
IDLE_CPU=1
NCPU=$(nproc)
int_childs() {
trap - INT
while IFS=$'
' read -r pid; do
kill -s SIGINT -$pid
done < <(jobs -p -r)
kill -s SIGINT -$$
}
# cmds is array that hold commands
# the complex thing is display which will handle all cmd output
# and serialized it correctly
trap int_childs INT
{
exec 2>&1
set -m
if [ $NCPU -gt $IDLE_CPU ]; then
for cmd in "${cmds[@]}"; do
$cmd &
while [ $(jobs -pr |wc -l) -ge $((NCPU - IDLE_CPU)) ]; do
wait -n
done
done
wait
else
for cmd in "${cmds[@]}"; do
$cmd
done
fi
} | display
解决方案 8:
您可能想看看runp。runp
这是一个简单的命令行工具,可以并行运行 (shell) 命令。当您想要一次运行多个命令以节省时间时,它很有用。它很容易安装,因为它是一个二进制文件。它已在 Linux(amd64 和 arm)和 MacOS/darwin(amd64)上进行了测试。
解决方案 9:
生成随机数很容易。假设您有一个像商店数据库这样的大文件,并且想要在某些特定基础上重写该文件。我的想法是计算核心数,将文件拆分成多少个核心,创建一个 script.cfg 文件,split.sh 和 recombine.sh split.sh 会将文件拆分成多少个核心,克隆 script.cfg(更改该大文件中内容的脚本),将 script.cgf 克隆到多少个核心,使它们可执行,在克隆中搜索和替换一些变量,这些变量必须知道要处理文件的哪一部分并在克隆完成后在后台运行它们,生成 clone$core.ok 文件,因此当所有克隆完成后,将告诉循环仅在生成所有 .ok 文件后将部分结果重新组合成一个结果。它可以通过“等待”来完成,但我喜欢我的方式
http://www.linux-romania.com/product.php?id_product=76
看底部,部分翻译成了英语,这样我就能在 2 分钟内处理 20000 篇 16 列的文章(四核),而不是 8 分钟(单核)。你必须关心 CPU 温度,因为所有核心都在 100% 运行
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件