Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在bash中并行运行有限数量的子进程?_Bash_Parallel Processing_Make_Xargs - Fatal编程技术网

在bash中并行运行有限数量的子进程?

在bash中并行运行有限数量的子进程?,bash,parallel-processing,make,xargs,Bash,Parallel Processing,Make,Xargs,我有一大组文件,需要进行一些繁重的处理。 这个处理是单线程的,使用几百个MiB的RAM(在用于启动作业的机器上),运行几分钟。 我当前的用例是在输入数据上启动hadoop作业,但我以前在其他情况下也遇到过同样的问题 为了充分利用可用的CPU能力,我希望能够并行运行几个这样的任务 但是,这样一个非常简单的示例shell脚本会由于过度的负载和交换而破坏系统性能: find . -type f | while read name ; do some_heavy_processing_comm

我有一大组文件,需要进行一些繁重的处理。 这个处理是单线程的,使用几百个MiB的RAM(在用于启动作业的机器上),运行几分钟。 我当前的用例是在输入数据上启动hadoop作业,但我以前在其他情况下也遇到过同样的问题

为了充分利用可用的CPU能力,我希望能够并行运行几个这样的任务

但是,这样一个非常简单的示例shell脚本会由于过度的负载和交换而破坏系统性能:

find . -type f | while read name ; 
do 
   some_heavy_processing_command ${name} &
done
所以我想要的基本上与“gmake-j4”的功能相似

我知道bash支持“wait”命令,但它只等待所有子进程完成。在过去,我创建了一个脚本,它执行一个“ps”命令,然后按名称将子进程grep出来(是的,我知道……很难看)

做我想做的事情最简单/最干净/最好的解决方案是什么


编辑:谢谢弗雷德里克:是的,这确实是 “xargs--max procs=4”就像一个符咒。 (所以我投票结束了我自己的问题)


弗雷德里克说得很好,沙格斯做的正是你想要的

这段代码对我来说非常有效

我注意到一个问题,脚本无法结束。 如果遇到由于max_jobs大于数组中的元素数而导致脚本无法结束的情况,脚本将永远不会退出

为了防止出现上述情况,我在“max_jobs”声明之后添加了以下内容

if [ $max_jobs -gt ${#todo_array[*]} ];
    then
           # there are more elements found in the array than max jobs, setting max jobs to #of array elements"
            max_jobs=${#todo_array[*]}
 fi

我知道我带着这个答案来参加聚会已经晚了,但我想我会发布一个替代方案,IMHO,使脚本的主体更加清晰和简单。(显然,您可以更改值2和5以适合您的场景。)


使用GNU并行,它变得更简单:

find . -type f | parallel  some_heavy_processing_command {}

了解更多信息:

我想我找到了一个更方便的解决方案,使用:

将其称为“test.mak”,并添加执行权限。如果调用
/test.mak
它将逐个调用
一些重处理命令。但是您可以调用as
/test.mak-j4
,然后它将同时运行四个子进程。此外,您还可以以更复杂的方式使用它:以
/test.mak-j5-l1.5
的形式运行,这样当系统负载低于1.5时,它将最多运行5个子进程,但如果系统负载超过1.5,它将限制进程数

它比标准分发版更灵活,并且是标准分发版的一部分,而不像另一个选项:

PARALLEL_MAX=...
function start_job() {
  while [ $(ps --no-headers -o pid --ppid=$$ | wc -l) -gt $PARALLEL_MAX ]; do
    sleep .1  # Wait for background tasks to complete.                         
  done
  "$@" &
}
start_job some_big_command1
start_job some_big_command2
start_job some_big_command3
start_job some_big_command4
...

这里有一个非常好的函数,我用来控制bash或ksh的最大作业数。注:pgrep中的-1减去wc-l子流程

function jobmax
{
    typeset -i MAXJOBS=$1
    sleep .1
    while (( ($(pgrep -P $$ | wc -l) - 1) >= $MAXJOBS ))
    do
        sleep .1
    done
}

nproc=5
for i in {1..100}
do
    sleep 1 &
    jobmax $nproc
done
wait # Wait for the rest

这看起来像是一项工作,但我不确定它是否为
xargs--max procs添加了额外的功能,我没有这样做know@Niels:我一直在使用
screen
,尽管这种方式有点混乱,尤其是从另一个
screen
会话开始时;)我现在理解了代码,但不得不想一想。特别是关于为什么这些将并行运行的部分(因为它们是子流程),我没有理解。我认为在代码中为这一部分添加注释也是值得的。尽管我当前的应用程序与xargs--max procs配合得很好,但我仍然认为您是“答案”,因为您的脚本在更多情况下都是可用的。谢谢,哥们,这真是太棒了!谢谢!:)在将while语法更改为:while[$(jobs | wc-l)-ge2]之后,这对我来说是有效的。请注意,该命令非常长,可能需要几行代码才能显示出来。在这种情况下,
jobs-p
应该可以做到这一点。
#!/usr/bin/make -f

THIS := $(lastword $(MAKEFILE_LIST))
TARGETS := $(shell find . -name '*.sh' -type f)

.PHONY: all $(TARGETS)

all: $(TARGETS)

$(TARGETS):
        some_heavy_processing_command $@

$(THIS): ; # Avoid to try to remake this makefile
PARALLEL_MAX=...
function start_job() {
  while [ $(ps --no-headers -o pid --ppid=$$ | wc -l) -gt $PARALLEL_MAX ]; do
    sleep .1  # Wait for background tasks to complete.                         
  done
  "$@" &
}
start_job some_big_command1
start_job some_big_command2
start_job some_big_command3
start_job some_big_command4
...
function jobmax
{
    typeset -i MAXJOBS=$1
    sleep .1
    while (( ($(pgrep -P $$ | wc -l) - 1) >= $MAXJOBS ))
    do
        sleep .1
    done
}

nproc=5
for i in {1..100}
do
    sleep 1 &
    jobmax $nproc
done
wait # Wait for the rest