多线程BASH编程 - 通用方法?

时间:2009-11-05 22:07:19

标签: multithreading bash shell mutex semaphore

好的,我在所有演示中都运行POV-Ray,但POV仍然是单线程的,并且不会使用多个核心。所以,我开始考虑BASH的解决方案。

我写了一个通用函数,它接受一个命令列表并在指定数量的子shell中运行它们。这实际上有效,但我不喜欢它以线程安全 多进程方式处理访问下一个命令的方式:

  • 作为参数,带有命令的文件(每行1个),
  • 要获取“下一个”命令,每个进程(“线程”)将:
    • 等待它可以创建一个锁定文件,其中包含: ln $ CMDFILE $ LOCKFILE
    • 从文件
    • 中读取命令
    • 删除第一行
    • 修改$ CMDFILE
    • 删除$ LOCKFILE。

有更简洁的方法吗?我无法让子shell正确读取FIFO中的单行。

<小时/> 顺便提一下,的重点是增强我在BASH命令行上可以做的事情,而不是找到非bash解决方案。我倾向于从命令行执行许多复杂的任务,并希望工具箱中有另一个工具。

同时,这是处理从文件中获取下一行的函数。如您所见,它每次读取/删除一行时都会修改磁盘文件。这似乎是hackish,但我没有想出更好的东西,因为FIFO不能用bash中的 setvbuf()工作。

#
# Get/remove the first line from FILE, using LOCK as a semaphore (with
# short sleep for collisions).  Returns the text on standard output,
# returns zero on success, non-zero when file is empty.
#
parallel__nextLine() 
{
  local line rest file=$1 lock=$2

  # Wait for lock...
  until ln "${file}" "${lock}" 2>/dev/null
  do sleep 1
     [ -s "${file}" ] || return $?
  done

  # Open, read one "line" save "rest" back to the file:
  exec 3<"$file"
  read line <&3 ; rest=$(cat<&3)
  exec 3<&-

  # After last line, make sure file is empty:
  ( [ -z "$rest" ] || echo "$rest" ) > "${file}"

  # Remove lock and 'return' the line read:
  rm -f "${lock}"
  [ -n "$line" ] && echo "$line"
}

4 个答案:

答案 0 :(得分:7)

#adjust these as required
args_per_proc=1 #1 is fine for long running tasks
procs_in_parallel=4

xargs -n$args_per_proc -P$procs_in_parallel povray < list

注意即将发布的coreutils nproc命令将自动确定 可用处理单元的数量,然后可以传递给-P

答案 1 :(得分:2)

如果您需要真正的线程安全性,我建议您迁移到更好的脚本系统。

例如,使用python,您可以使用信号量/队列创建具有安全同步的真实线程。

答案 2 :(得分:2)

很抱歉在这么久之后碰到了这个,但我为这个IMO拼凑了一个相当不错的解决方案 它不能很好地工作,但它会将脚本限制为运行一定数量的子任务,然后在最后等待所有其余的任务。

#!/bin/bash

pids=()
thread() {
  local this
  while [ ${#} -gt 6 ]; do
    this=${1}
    wait "$this"
    shift
  done
  pids=($1 $2 $3 $4 $5 $6)
}
for i in 1 2 3 4 5 6 7 8 9 10
do
  sleep 5 &
  pids=( ${pids[@]-} $(echo $!) )
  thread ${pids[@]}
done
for pid in ${pids[@]}
do
  wait "$pid"
done

它似乎非常适合我正在做的事情(一次处理并行上传一堆文件)并防止它破坏我的服务器,同时仍然确保所有文件在完成脚本之前上传

答案 3 :(得分:0)

我相信你实际上是在这里分配流程,而不是线程化。我建议您使用其他脚本语言(例如perlpythonruby)寻找线程支持。