并行函数的最后一个实例的状态

问题描述 投票:0回答:3

我正在寻找一种并行运行函数并准确知道所有函数实例何时完成的方法。 我添加了一个微调器(函数的实例运行不同的时间,取决于变量,所以我需要在屏幕上看到一些东西)并按以下方式尝试:

for a in "${ARRAY[@]}"; do
    spin='/-\|'
    while true; do
        i=$(( (i+1) %4 )); printf "\r[ ${spin:$i:1} ] "; sleep .3;
    done & someFunction & 
    kill $!; trap 'kill $!' SIGTERM
done

但是

someFunction
不起作用。我认为是因为如果它被触发为
someFunction &
它会立即被下一个代码行杀死。而且脚本结束后,旋转器将在 CLI 上永远工作。

如何同时运行

someFunction
,等到最后一个实例完成,并保持旋转直到那时?

linux bash shell scripting
3个回答
0
投票

您需要跟踪您已分叉的进程,然后为它们进行

wait
wait
命令非常灵活,还可以一次等待所有后台作业(而不是一个接一个)或仅等待特定作业。请参阅
man bash
,第
SHELL BUILTIN COMMANDS
部分。以下脚本启动一个旋转器,每秒打印一些内容,然后分叉出 5 个睡眠不同时间的进程。

spinner() { for ((;;)); do sleep 1; printf '<spin>'; done; }
someFunction() { sleep "$1"; }

spinner &
spinner_pid="$!"
for ((i = 2; i < 12; i += 2)); do
  someFunction "$i"&
  function_pids["$!"]="$i"
done

while ((${#function_pids[@]})); do
  wait -n -p pid && echo -n  'finished: ' || echo -n 'failed: '
  echo "${function_pids[pid]}"
  unset 'function_pids[pid]'
done
kill -TERM "$spinner_pid"
wait -n "$spinner_pid" || :

0
投票

由于 Bash 管理后台进程的方式,通过 PID 杀死进程通常有很小的可能性会杀死错误的进程。如果您使用的是 Bash 4.3(2014 年发布)或更高版本,请尝试此免杀代码:

#! /bin/bash -p

# FIXME: Define the 'args' array and the 'someFunction' function

# Run a spinner as a coprocess
coproc spinner \
{
    declare -r spin='/-\|'
    declare i=0
    while read -r -t 0.3 _; (( $? > 128 )); do
        printf '\r[ %s ] ' "${spin:i++%4:1}" >&2
    done
}

# Disown the spinner coprocess so 'wait' will not wait for it to exit
disown %% 

for a in "${args[@]}"; do
    someFunction "$a" & 
done

# Wait for all background processes (except the disowned spinner) to exit
wait

# Close the pipe to the spinner.  It will read EOF and close.
exec {spinner[1]}>&-
  • 将旋转器作为协进程运行,可以通过关闭其输入管道来停止它,而不是杀死它。它还可以disown旋转器进程,因此wait不会等待它退出。
  • read文档中所述,如果
    read -r -t 0.3 _
    在0.3秒内未能读取输入行,则会返回大于128的状态。使用
    read
    而不是
    sleep
    来表示微调器中的延迟,可以避免每次延迟都运行子进程,从而节省资源。
  • 最好避免使用 ALL_UPPERCASE 变量名,因为存在与 shell 编程中使用的大量特殊 ALL_UPPERCASE 变量发生冲突的危险。请参阅正确的 Bash 和 shell 脚本变量大写。这就是为什么我将原始代码中的
    ARRAY
    替换为
    args

0
投票

我觉得大家有点想多了...

(
for a in "${ARRAY[@]}"; do
    someFunction & 
done
wait
) &
GRP=$!
spin='/-\|'
while true
do
    i=$(( (i+1) %4 )); printf "\r[ ${spin:$i:1} ] "
done &
SPINNER=$!
wait $GRP
kill $SPINNER
© www.soinside.com 2019 - 2024. All rights reserved.