分叉/多线程过程| 巴什

Gre*_*reg 47 bash shell fork

我想让我的代码的一部分更有效率.我正在考虑将它分成多个进程并让它们一次执行50/100次而不是一次.

例如(伪):

for line in file;
do 
foo;
foo2;
foo3;
done
Run Code Online (Sandbox Code Playgroud)

我想这个for循环运行多次.我知道这可以通过分叉来完成.它看起来像这样吗?

while(x <= 50)
parent(child pid)
{
   fork child()
}
child
{
   do 
   foo; foo2; foo3; 
   done
   return child_pid()
}
Run Code Online (Sandbox Code Playgroud)

或者我是否以错误的方式思考这个问题?

谢谢!

Ale*_*huk 52

在bash脚本(非交互式)中,默认情况下JOB CONTROL被禁用,因此您无法执行命令:job,fg和bg.

这对我有用:

#!/bin/sh

set -m # Enable Job Control

for i in `seq 30`; do # start 30 jobs in parallel
  sleep 3 &
done

# Wait for all parallel jobs to finish
while [ 1 ]; do fg 2> /dev/null; [ $? == 1 ] && break; done
Run Code Online (Sandbox Code Playgroud)

最后一行使用"fg"将后台作业带到前台.它在一个循环中执行此操作,直到fg返回1($?== 1),它在不再有任何后台作业时执行.

  • 在bash脚本中,你可以使用`wait`,例如:`sleep 3&WAITPID = $!; 等待$ WAITPID`,或以这种方式汇总pids`WAITPIDS ="$ WAITPIDS"$!; ...; 等待$ WAITPIDS` (18认同)
  • 或者只是"等待". (11认同)

mob*_*mob 29

我不知道fork在bash中有任何明确的调用.您可能想要做的是附加& 到要在后台运行的命令.您还可以使用&在bash脚本中定义的函数:

do_something_with_line()
{
  line=$1
  foo
  foo2
  foo3
}

for line in file
do
  do_something_with_line $line &
done
Run Code Online (Sandbox Code Playgroud)

编辑:为了限制同时后台进程的数量,你可以尝试这样的事情:

for line in file
do
  while [`jobs | wc -l` -ge 50 ]
  do
    sleep 5
  done
  do_something_with_line $line &
done
Run Code Online (Sandbox Code Playgroud)

  • +1暴徒.我将其修改为一个函数,在您放入后台的任何内容之后添加到命令文件中.然后你可以按顺序在文件中运行一些命令,只在后台运行一些命令:#!/ bin/bash waitpid(){while [[`jobs | wc -l` -ge $ 1]]; 做睡觉1; 完成; } (2认同)

Ole*_*nge 18

使用GNU Parallel,您可以:

cat file | parallel 'foo {}; foo2 {}; foo3 {}'
Run Code Online (Sandbox Code Playgroud)

这将在每个cpu核心上运行一个作业.运行50做:

cat file | parallel -j 50 'foo {}; foo2 {}; foo3 {}'
Run Code Online (Sandbox Code Playgroud)

观看介绍视频以了解更多信息:

http://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

  • 除了唠叨屏幕,并行非常酷. (3认同)

har*_*dsv 17

我不喜欢使用,wait因为它会在进程退出之前被阻塞,这在有多个进程需要等待时并不理想,因为在当前进程完成之前我无法获得状态更新.我更喜欢使用kill -0和之相结合sleep.

鉴于pids要等待的数组,我使用以下waitPids()函数来获得有关哪些pids仍未完成的持续反馈.

declare -a pids
waitPids() {
    while [ ${#pids[@]} -ne 0 ]; do
        echo "Waiting for pids: ${pids[@]}"
        local range=$(eval echo {0..$((${#pids[@]}-1))})
        local i
        for i in $range; do
            if ! kill -0 ${pids[$i]} 2> /dev/null; then
                echo "Done -- ${pids[$i]}"
                unset pids[$i]
            fi
        done
        pids=("${pids[@]}") # Expunge nulls created by unset.
        sleep 1
    done
    echo "Done!"
}
Run Code Online (Sandbox Code Playgroud)

当我在后台启动一个进程时,我pids使用下面的实用程序函数将其pid立即添加到数组中:

addPid() {
    local desc=$1
    local pid=$2
    echo "$desc -- $pid"
    pids=(${pids[@]} $pid)
}
Run Code Online (Sandbox Code Playgroud)

以下示例说明如何使用:

for i in {2..5}; do
    sleep $i &
    addPid "Sleep for $i" $!
done
waitPids
Run Code Online (Sandbox Code Playgroud)

以下是反馈的内容:

Sleep for 2 -- 36271
Sleep for 3 -- 36272
Sleep for 4 -- 36273
Sleep for 5 -- 36274
Waiting for pids: 36271 36272 36273 36274
Waiting for pids: 36271 36272 36273 36274
Waiting for pids: 36271 36272 36273 36274
Done -- 36271
Waiting for pids: 36272 36273 36274
Done -- 36272
Waiting for pids: 36273 36274
Done -- 36273
Waiting for pids: 36274
Done -- 36274
Done!
Run Code Online (Sandbox Code Playgroud)


Mic*_*ker 2

让我尝试一下例子

for x in 1 2 3 ; do { echo a $x ; sleep 1 ; echo b $x ; } &  done ; sleep 10
Run Code Online (Sandbox Code Playgroud)

并用于jobs查看正在运行的内容。