Bash `wait` 命令,等待超过 1 个 PID 完成执行

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/40377623/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 15:21:28  来源:igfitidea点击:

Bash `wait` command, waiting for more than 1 PID to finish execution

linuxbashwaitpid

提问by user3728501

I recently posted a question asking if it was possible to prevent PID's from being re-used.

我最近发布了一个问题,询问是否可以防止重复使用 PID

So far the answer appears to be no. (Which is fine.)

到目前为止,答案似乎是否定的。(这很好。)

However, the user Diego Torres Milanoadded an answer to that question, and my question here is in regards to that answer.

但是,用户Diego Torres Milano添加了该问题的答案,我在这里的问题是关于该答案的。

Diego answered,

迭戈回答说

If you are afraid of reusing PID's, which won't happen if you wait as other answers explain, you can use

echo 4194303 > /proc/sys/kernel/pid_max

to decrease your fear ;-)

如果您害怕重复使用 PID,如果您等待其他答案的解释就不会发生这种情况,您可以使用

echo 4194303 > /proc/sys/kernel/pid_max

减少你的恐惧;-)

I don't actually understand why Diego has used the number 4194303here, but that's another question.

我实际上不明白为什么迭戈在4194303这里使用这个数字,但这是另一个问题。

My understanding was that I had a problem with the following code:

我的理解是我遇到了以下代码的问题:

for pid in "${PIDS[@]}"
do
    wait $pid
done

The problem being that I have multiple PIDs in an array, and that the for loop will run the waitcommand sequentially with each PID in the array, however I cannot predict that the processes will finish in the same order that their PIDs are stored in this array.

问题是我在一个数组中有多个 PID,并且 for 循环将wait使用数组中的每个 PID 按顺序运行命令,但是我无法预测进程将按照其 PID 存储在该数组中的相同顺序完成.

ie; the following couldhappen:

IE; 可能会发生以下情况:

  • Start waiting for PID in array index 0
  • Process with PID in index 1 of array terminates
  • New job(s) run on system, resulting in PID which is stored in index 1 of PID array being reused for another process
  • waitterminates as PID in array index 0 exits
  • Start waiting for PID in array index 0, except this is now a different process and we have no idea what it is
  • The process which was run which re-used the PID which waitis currently waiting for neverterminates. Perhaps it is the PID of a mail server or something which a system admin has started.
  • waitkeeps waiting until the next serious linux bug is found and the system is rebooted or there is a power outage
  • 开始等待数组索引 0 中的 PID
  • PID 在数组索引 1 中的进程终止
  • 新作业在系统上运行,导致存储在 PID 数组索引 1 中的 PID 被另一个进程重用
  • wait终止为数组索引 0 中的 PID 退出
  • 开始在数组索引 0 中等待 PID,除了现在这是一个不同的过程,我们不知道它是什么
  • 重新使用wait当前正在等待的 PID 的运行进程永远不会终止。也许它是邮件服务器的 PID 或系统管理员已启动的东西。
  • wait一直等到发现下一个严重的 linux 错误并重新启动系统或停电

Diego said:

迭戈说:

which won't happen if you wait as other answers explain

如果您等待其他答案的解释,这将不会发生

ie; that the situation I have described above cannot happen.

IE; 我上面描述的情况不会发生。

Is Diego correct?

迭戈正确吗?

  • If so, why can the situation I discribed above not occur?
  • 如果是这样,为什么我上面描述的情况不会发生?

Or is Diego not correct?

还是迭戈不正确?

  • If so, well, then I post a new question later today...
  • 如果是这样,那么我今天晚些时候发布一个新问题......

Additional notes

补充说明

It has occured to me that this question might be confusing, unless you are aware that the PID's are PID's of processes launched in the background. ie;

我发现这个问题可能会令人困惑,除非您知道 PID 是在后台启动的进程的 PID。IE;

my_function &
PID="$!"
PIDS+=($PID)

回答by chepner

Let's go through your options.

让我们来看看你的选择。

Wait for all background jobs, unconditionally

无条件等待所有后台作业

for i in 1 2 3 4 5; do
    cmd &
done
wait

This has the benefit of being simple, but you can't keep your machine busy. If you want to start new jobs as old ones complete, you can't. You machine gets less and less utilized until all the background jobs complete, at which point you can start a new batch of jobs.

这样做的好处是简单,但你不能让你的机器忙碌。如果你想在旧工作完成后开始新工作,你不能。在所有后台作业完成之前,您的机器利用率越来越低,此时您可以开始新的一批作业。

Related is the ability to wait for a subset of jobs by passing multiple arguments to 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

Wait for individual jobs in arbitrary order

以任意顺序等待单个作业

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

This has the benefit of letting you do work after a job completes, but still has the problem that jobs otherthan $pidmight complete first, leaving your machine underutilized until $pidactually completes. You do, however, still get the exit status for each individual job, even if it completes before you actually wait for it.

这有让你在作业完成后做工作的好处,但仍然有就业问题,其他$pid可能先完成,让你的机器得到充分利用,直到$pid实际完成。但是,您仍然可以获得每个单独作业的退出状态,即使它在您实际等待之前完成。

Wait for the nextjob to complete (bash4.3 or later)

等待下一个作业完成(bash4.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

Here, you can wait until ajob completes, which means you can keep your machine as busy as possible. The only problem is, you don't necessarily know whichjob completed, without using jobsto get the list of active processes and comparing it to pids.

在这里,你可以等到一个任务完成,这意味着你可以让你的机器尽可能忙。唯一的问题是,你不一定知道哪些作业已完成,而无需使用jobs来获得活动进程的列表,并将其与pids

Other options?

其他选择?

The shell by itself is not an ideal platform for doing job distribution, which is why there are a multitude of programs designed for managing batch jobs: xargs, parallel, slurm, qsub, etc.

通过自身的外壳是不是做的工作分配一个理想的平台,这就是为什么有设计用于管理批处理作业程序的众多:xargsparallelslurmqsub,等。

回答by sqweek

This is old, but the scenario presented where a deferred waitwaits for some random unrelated process due to pid collision hasn't been directly addressed.

这是旧的,但是wait由于 pid 冲突,延迟等待一些随机的无关进程的情况还没有直接解决。

It's not possible at the kernel level. The way it works there is that prior to the parent process calling wait(2)1, the child process still exists. Because the child still exists, linux will run out of pids rather than reuse it. This manifests at times with so called zombie or "defunct" processes - these are children which have exited but have yet to be "reaped" by their parent.

这在内核级别是不可能的。它的工作方式是在父进程调用wait(2)1 之前,子进程仍然存在。因为孩子仍然存在,linux 将耗尽 pids 而不是重用它。这有时会通过所谓的僵尸或“失效”进程表现出来 - 这些是已经退出但尚未被其父进程“收割”的子进程。

Now, at the shell level you don't have to call wait(1)1 for child processes to be reaped - bashdoes this automatically. I haven't confirmed, but when you run wait $pidfor a child pid which exited long ago, I would wager bashrealises it has already reaped that child and returns the information immediately rather than waiting for anything.

现在,在 shell 级别,您不必wait(1)为要收割的子进程调用1 -bash自动执行此操作。我还没有确认,但是当你运行wait $pid一个很久以前退出的孩子 pid 时,我敢打赌bash意识到它已经收获了那个孩子并立即返回信息而不是等待任何东西。

1 the wait(N)notation is a convention used to disambiguate between API layers - N refers to the section of the manual a command/function is located in. In this case we have:

1wait(N)表示法是用于消除 API 层之间歧义的约定 - N 指的是手册中命令/函数所在的部分。在这种情况下,我们有:

  • wait(2): the syscall - see man 2 wait
  • wait(1): the shell command - see man 1 waitor help wait
  • wait(2):系统调用 - 见 man 2 wait
  • wait(1): shell 命令 - 请参阅man 1 waithelp wait

If you want to know what lives in each manual section, try man N intro.

如果您想知道每个手册部分中的内容,请尝试man N intro.