11

我正在 shell 中编写一个脚本,其中一个命令正在运行并且需要 2 分钟。每次。此外,我们对此无能为力。但是如果我想在脚本中运行这个命令 100 次,那么总时间将是 200 分钟。这将产生一个大问题。没有人愿意等待 200 分钟。我想要的是并行运行所有 100 个命令,以便输出将在 2 分钟内出现,或者可能需要更多时间,但不需要 200 分钟。

如果有任何机构可以以任何方式帮助我,我们将不胜感激。

4

3 回答 3

16

GNU Parallel就是你想要的,除非你想重新发明轮子。这里有一些更详细的例子,但很短:

ls | parallel gzip # gzip all files in a directory
于 2012-06-21T04:43:31.990 回答
13

...并行运行所有 100 个命令,以便输出将在 2 分钟内出现

这只有在您的系统上有 200 个处理器时才有可能。

shell 脚本中没有这样的实用程序/命令来并行运行命令。你可以做的是在后台运行你的命令:

for ((i=0;i<200;i++))
do
   MyCommand &
done

使用&(背景),每次执行都会尽快安排。但这并不能保证您的代码将在 200 分钟内执行完毕。这取决于您的系统上有多少个处理器。

如果您只有一个处理器,并且每次执行命令(需要 2 分钟)都在 2 分钟内进行一些计算,那么处理器正在做一些工作,这意味着没有浪费任何周期。在这种情况下,并行运行命令并没有帮助,因为只有一个处理器也不是空闲的。因此,这些进程将只是等待轮到它们执行。

如果您有多个处理器,那么上述方法(for 循环)可能有助于减少总执行时间。

于 2012-06-18T16:58:56.817 回答
7

As @KingsIndian said, you can background tasks, which sort of lets them run in parallel. Beyond this, you can also keep track of them by process ID:

#!/bin/bash

# Function to be backgrounded
track() {
  sleep $1
  printf "\nFinished: %d\n" "$1"
}

start=$(date '+%s')

rand3="$(jot -s\  -r 3 5 10)"

# If you don't have `jot` (*BSD/OSX), substitute your own numbers here.
#rand3="5 8 10"

echo "Random numbers: $rand3"

# Make an associative array in which you'll record pids.
declare -A pids

# Background an instance of the track() function for each number, record the pid.
for n in $rand3; do
  track $n &
  pid=$!
  echo "Backgrounded: $n (pid=$pid)"
  pids[$pid]=$n
done

# Watch your stable of backgrounded processes.
# If a pid goes away, remove it from the array.
while [ -n "${pids[*]}" ]; do
  sleep 1
  for pid in "${!pids[@]}"; do
    if ! ps "$pid" >/dev/null; then
      unset pids[$pid]
      echo "unset: $pid"
    fi
  done
  if [ -z "${!pids[*]}" ]; then
    break
  fi
  printf "\rStill waiting for: %s ... " "${pids[*]}"
done

printf "\r%-25s \n" "Done."
printf "Total runtime: %d seconds\n" "$((`date '+%s'` - $start))"

You should also take a look at the Bash documentation on coprocesses.

于 2012-06-18T18:06:59.590 回答