Bash 线程:等待所有作业线程完成不起作用?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2259867/
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
Bash threading: wait for all job threads to finish doesn't work?
提问by Gargauth
I'm writing a little script, that will create archives in main thread and after each archive is complete, a new thread would be created by calling function that would take care of uploading these archives. The reason I want uploading to be done in background is so that another archive could be created while the previous archives are being uploaded.
我正在编写一个小脚本,它将在主线程中创建档案,在每个档案完成后,将通过调用负责上传这些档案的函数来创建一个新线程。我希望在后台完成上传的原因是,可以在上传以前的档案时创建另一个档案。
The problem I'm having is at the very end of the script. That is, main thread don't wait for all uploading threads to finish before exiting. Look at the following simplified script (I removed/changed parts of the code not related to the problem)
我遇到的问题是在脚本的最后。也就是说,主线程在退出之前不会等待所有上传线程完成。查看以下简化脚本(我删除/更改了与问题无关的代码部分)
function func {
for files in /home/somewhere/
do
echo "Uploading " &
done
wait
}
find /home/some/path -type f | while read filename ; do
echo "Creating archive of $filename"
func $somevariable &
done
wait
Everything is executing very nicely until the last archive is created, then the script ends before all functhreads finish, leaving many files not uploaded.
一切都很好地执行,直到创建最后一个存档,然后脚本在所有func线程完成之前结束,留下许多文件没有上传。
Thank you for your ideas.
谢谢你的想法。
回答by DigitalRoss
Update: good points in the comment.
更新:评论中的好点。
So, on a second look, it turns out the problem is the subshell that is created by the pipe to the loop. It's a good way to structure the script but you need to do the final wait in the shell that spun off the background tasks.
因此,再看一看,原来问题是由管道到循环创建的子外壳。这是构建脚本的好方法,但您需要在分离后台任务的 shell 中进行最后的等待。
So do something like this:
所以做这样的事情:
find /home/some/path -type f | (while read filename; do
echo "Creating archive of $filename"
func $somevariable &
done
wait
)
回答by dubiousjim
Tricky! The problem is that this block
棘手!问题是这个块
find /home/some/path -type f | while read filename ; do
...
done
Creates a subshell. The func $somevariable jobs are created in that subshell. The parent shell sees that all the background jobs itcreated have finished, it doesn't keep track of background jobs created by subshells it spawned.
创建一个子外壳。func $somevariable 作业是在该子shell 中创建的。父 shell 看到它创建的所有后台作业都已完成,它不会跟踪由它生成的子 shell 创建的后台作业。
The easiest fix is to create your background jobs from the parent shell instead. You can avoid creating a subshell by not using a pipe:
最简单的解决方法是从父 shell 创建后台作业。您可以通过不使用管道来避免创建子外壳:
while read filename ; do
...
done < <(find /home/some/path -type f)
Well, that creates asubshell---for the find---but the while block is no longer in a subshell.
好吧,这会创建一个子外壳——用于查找——但是 while 块不再位于子外壳中。
Note that the above works only under bash. (Don't know about ksh or zsh, perhaps it works there too. But it won't work under ash and other sh derivatives.)
请注意,以上仅在 bash 下有效。(不知道 ksh 或 zsh,也许它也可以在那里工作。但它不会在 ash 和其他 sh 衍生物下工作。)
回答by Stephen C
If you execute waitwith no arguments, it is supposed to wait for currently active child processes to complete.
如果不wait带参数执行,它应该等待当前活动的子进程完成。
The problem is likely to be that "all currently active child processes" does not mean what you think it means in this context. In particular, if you create pipelines in a subshell it is not entirely clear if they would be waited for in the parent shell.
问题很可能是“所有当前活动的子进程”在这种情况下并不意味着您认为它的含义。特别是,如果您在子 shell 中创建管道,则不完全清楚它们是否会在父 shell 中等待。
I suspect that waitactually only waits for processes / pipelines that show up in the output of jobs. Try some experiments ...
我怀疑wait实际上只等待出现在jobs. 尝试一些实验...
A possible alternative may be to capture the child process ids and do a wait ncall for each id.
一种可能的替代方法是捕获子进程 ID 并wait n为每个 ID 调用一次。
回答by Philluminati
You could loop until the jobscommand returns nothing as an alternative method.
jobs作为替代方法,您可以循环直到命令不返回任何内容。
回答by Pablo Niklas
You could try this script. It does precisely that. https://github.com/pabloniklas/BASH/blob/master/lib_cpu.sh
你可以试试这个脚本。它正是这样做的。 https://github.com/pabloniklas/BASH/blob/master/lib_cpu.sh

