[英]Bash `wait` command, waiting for more than 1 PID to finish execution
我最近发布了一个问题,询问是否可以防止重复使用 PID 。
到目前为止,答案似乎是否定的。 (这很好。)
但是,用户Diego Torres Milano为该问题添加了一个答案,我在这里的问题与该答案有关。
迭戈回答说
如果您害怕重复使用 PID,如果您等待其他答案的解释就不会发生这种情况,您可以使用
echo 4194303 > /proc/sys/kernel/pid_max
减少你的恐惧;-)
我实际上不明白为什么迭戈在这里使用了数字4194303
,但这是另一个问题。
我的理解是我遇到了以下代码的问题:
for pid in "${PIDS[@]}"
do
wait $pid
done
问题是我在一个数组中有多个 PID,并且 for 循环将与数组中的每个 PID 按顺序运行wait
命令,但是我无法预测进程将按照其 PID 存储在此的相同顺序完成大批。
IE; 可能会发生以下情况:
wait
终止,因为数组索引 0 中的 PID 退出wait
当前等待的 PID 的进程永远不会终止。 也许它是邮件服务器的 PID 或系统管理员已启动的东西。wait
一直等到发现下一个严重的 linux 错误并且系统重新启动或停电迭戈说:
如果您等待其他答案的解释,这将不会发生
IE; 我上面描述的情况不会发生。
迭戈正确吗?
还是迭戈不正确?
我发现这个问题可能会令人困惑,除非您知道 PID 是在后台启动的进程的 PID。 IE;
my_function &
PID="$!"
PIDS+=($PID)
让我们来看看你的选择。
for i in 1 2 3 4 5; do
cmd &
done
wait
这样做的好处是简单,但你不能让你的机器忙碌。 如果你想在旧工作完成后开始新工作,你不能。 在所有后台作业完成之前,您的机器利用率越来越低,此时您可以开始新的一批作业。
相关的是通过将多个参数传递给wait
来wait
作业子集的能力:
unrelated_job &
for i in 1 2 3 4 5; do
cmd & pids+=($!)
done
wait "${pids[@]}" # Does not wait for unrelated_job, though
for i in 1 2 3 4 5; do
cmd & pids+=($!)
done
for pid in "${pids[@]}"; do
wait "$pid"
# do something when a job completes
done
这有让你在作业完成后做工作的好处,但仍然有比其他工作问题$pid
可能会先完成,让你的机器得到充分利用,直到$pid
实际完成。 但是,您仍然可以获得每个单独作业的退出状态,即使它在您实际等待之前完成。
bash
4.3 或更高版本)for i in 1 2 3 4 5; do
cmd & pids+=($!)
done
for pid in "${pids[@]}"; do
wait -n
# do something when a job completes
done
在这里,你可以等到工作完成,这意味着你可以让你的机器尽可能忙。 唯一的问题是,您不一定知道完成了哪个作业,而无需使用jobs
来获取活动进程列表并将其与pids
进行比较。
shell 本身并不是进行作业分配的理想平台,这就是为什么有许多程序设计用于管理批处理作业: xargs
、 parallel
、 slurm
、 qsub
等。
这是旧的,但是由于pid冲突而延迟wait
等待一些随机无关进程的情况尚未直接解决。
这在内核级别是不可能的。 它的工作方式是在父进程调用wait(2)
¹ 之前,子进程仍然存在。 因为孩子仍然存在,linux 将耗尽 pids 而不是重用它。 这有时会通过所谓的僵尸或“失效”进程表现出来 - 这些是已经退出但尚未被其父进程“收割”的子进程。
现在,在 shell 级别,您不必为要收割的子进程调用wait(1)
¹ - bash
会自动执行此操作。 我还没有确认,但是当你为一个很久以前退出的孩子 pid 运行wait $pid
,我敢打赌bash
意识到它已经收获了那个孩子并立即返回信息而不是等待任何东西。
¹ wait(N)
表示法是用于消除 API 层之间歧义的约定 - N 指的是命令/函数所在的手册部分。在这种情况下,我们有:
wait(2)
:系统调用 - 参见man 2 wait
wait(1)
:shell 命令 - 参见man 1 wait
或help wait
如果您想知道每个手册部分中的内容,请尝试man N intro
。
从Bash 5.1开始,由于引入了wait -p
,现在有一种处理多个后台作业的额外方法。
下面是一个例子:
#!/usr/bin/env bash
for ((i=0; i < 10; i++)); do
secs=$((RANDOM % 10)); code=$((RANDOM % 256))
(sleep ${secs}; exit ${code}) &
echo "Started background job (pid: $!, sleep: ${secs}, code: ${code})"
done
while true; do
wait -n -p pid; code=$?
[[ -z "${pid}" ]] && break
echo "Background job ${pid} finished with code ${code}"
done
这里的新奇之处在于,您现在确切地知道完成了哪一项后台作业。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.