【问题标题】:Running shell script in parallel并行运行 shell 脚本
【发布时间】:2011-04-05 05:54:17
【问题描述】:

我有一个shell脚本

  1. 随机播放一个大文本文件(600 万行和 6 列)
  2. 根据第一列对文件进行排序
  3. 输出1000个文件

所以伪代码是这样的

file1.sh 

#!/bin/bash
for i in $(seq 1 1000)
do

  Generating random numbers here , sorting  and outputting to file$i.txt  

done

有没有办法在parallel 中运行这个shell 脚本来充分利用多核CPU?

目前,./file1.sh 依次执行 1 到 1000 次,非常慢。

感谢您的帮助。

【问题讨论】:

  • 如果你发现自己需要在 shell 脚本中做任何不重要的事情(例如多处理等),是时候用适当的编程语言重写它了。

标签: linux bash shell unix parallel-processing


【解决方案1】:

另一个非常方便的方法是使用gnu parallel,如果您还没有它,那么非常值得安装它;如果任务不一定花费相同的时间,这是非常宝贵的。

seq 1000 | parallel -j 8 --workdir $PWD ./myrun {}

将启动./myrun 1./myrun 2 等,确保一次运行 8 个作业。如果您想一次在多个节点上运行,它也可以获取节点列表,例如在 PBS 作业中;我们对用户如何在我们的系统上执行此操作的说明是here

更新添加:您要确保您使用的是 gnu-parallel,而不是 moreutils 包中同名的更有限的实用程序(两者的不同历史是描述了here。)

【讨论】:

  • @Jonathan- 感谢您的指点。我将要求我的系统管理员安装 GNU 并行。在系统上似乎是一个有用的实用程序。实际上我打算在 PBS 上发布这个问题,但你已经回答了。干杯
  • 如果您的系统管理员不会安装它,那么您自己安装很容易:只需将 perl 脚本“并行”复制到路径中的目录即可。无需编译或安装库。
  • @Ole - 感谢您的提示。我的系统管理员已同意在系统上安装它。
  • @Jonathan- 当您提到 ./myrun 时,它是带有“&”和“wait”的修改后的脚本,还是没有它们的,即原始的 shell 脚本?干杯
  • 原来 moreutils 包不包括 gnu-parallel 而是 Tollef 的;工具的演变历史在gnu.org/software/parallel/history.html
【解决方案2】:

查看bash subshells,这些可用于并行运行部分脚本。

我没有对此进行测试,但这可能是一个开始:

#!/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

【讨论】:

  • 这将并行启动所有数千个任务,这可能会导致过多的交换/争用以获得最佳工作吞吐量,但这无疑是一种合理且简单的入门方式。
  • 好点!最简单的解决方案是有一个外部循环来限制启动子shell 的数量和它们之间的wait
  • @Anders: 或者只是在上面循环中的“完成”之前添加一个“if (( $i % 10 == 0 )); then wait;fi”...
  • @Tony:我认为把它留在里面是有意义的。wait 没有运行子shell 似乎什么都不做,如果选择的并发子shell 数量不是数量的一个因素当循环结束时,我们可能会得到仍在运行的活动子shell。
  • 如果所有作业都花费完全相同的时间,则此解决方案效果最佳。如果作业花费的时间不同,您将浪费 CPU 时间来等待其中一项较长的作业完成。换句话说:它不会一直保持 10 个作业同时运行。
【解决方案3】:

为了让事情并行运行,你可以在 shell 命令末尾使用 '&' 在后台运行它,然后wait 默认情况下(即不带参数)将等待所有后台进程完成。所以,也许并行开始 10 个,然后等待,然后再做 10 个。您可以使用两个嵌套循环轻松完成此操作。

【讨论】:

  • 非常感谢您的建议。现在所有 CPU 都在工作。你知道如何让它跨节点运行吗?我正在使用节点=2:ppn=8 的 PBS 将作业提交给高性能计算,但只有 1 个节点在工作。
  • @Tony:直到现在我才听说过 PBS……听起来很有趣,但我不知道如何使用它。对不起!
  • 关于 PBS 问题和跨节点,请参阅stackoverflow.com/questions/5453427/…
  • WAIT 是如何工作的?你能用一个例子更新你的答案吗?我想在某个函数中运行多个线程,但是在所有这些线程都完成之前,下一个函数不能启动。
  • @d-b wait 等待后台进程完成,而不是线程。例如,for FILE in huge.txt massive.log enormous.xml; do scp $FILE someuser@somehost:/tmp/ &; done; wait; echo "finished" 将运行三个scp(安全复制)进程,将三个文件并行复制到删除主机的/tmp 目录中,并在所有三个复制完成后才输出"finished"
【解决方案4】:

在 GNU 并行的文档中,有一个 whole list of programs 可以从 shell 并行运行作业,甚至包括它们之间的比较。有很多很多的解决方案。另一个好消息是,它们在调度作业方面可能非常有效,因此所有内核/处理器始终保持忙碌。

【讨论】:

    【解决方案5】:

    有一个简单的、可移植的程序可以为您做到这一点:PPSS。 PPSS 会自动为您安排作业,方法是检查有多少内核可用,并在另一个作业刚完成时启动另一个作业。

    【讨论】:

      【解决方案6】:
      IDLE_CPU=1
      NCPU=$(nproc)
      
      int_childs() {
          trap - INT
          while IFS=$'\n' 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
      

      【讨论】:

        【解决方案7】:

        您可能想看看runprunp 是一个简单的命令行工具,可以并行运行(shell)命令。当您想一次运行多个命令以节省时间时,它很有用。它很容易安装,因为它是一个二进制文件。它已经在 Linux(amd64 和 arm)和 MacOS/darwin (amd64) 上进行了测试。

        【讨论】:

          【解决方案8】:

          生成随机数很容易。 假设您有一个像商店数据库这样的大文件,并且您想在某些特定基础上重写该文件。 我的想法是计算核心数,将文件拆分为多少个核心,制作一个 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% 运行

          【讨论】:

          • 用英语怎么说?请不要发短信说话,你,因为,......你当然打出了其他词,但不是小词 - 显然是懒惰!
          • 加上链接坏了。
          猜你喜欢
          • 2013-08-14
          • 2017-09-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-08-25
          • 2012-01-15
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多