- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我有许多执行许多类似任务的 bash 脚本,它们使用一些外部二进制程序。问题是二进制程序通常不会像它们应该的那样退出终止。由于我的脚本运行了数千次,因此这些进程的大量闲置/几乎死亡的实例很快就会累积起来。我无法修复这些程序,因此我需要确保我的 bash 脚本正在终止它们。
SE 中已经有一些主题处理终止 bash 脚本进程的任务。我已经应用并测试了那里写的东西,并且在某种程度上它是有效的。但它对我的情况来说效果不够好,我不明白为什么,因此我提出了一个新问题。
我的脚本有一个层次结构,这里以简化的方式显示:脚本 A 调用脚本 B,脚本 B 并行调用脚本 C 的多个实例以使用所有 CPU。例如。脚本 B 并行运行脚本 C 的 5 个实例,当脚本 C 的一个实例完成时,它会启动一个新实例,总共运行数千次脚本 C。脚本 C 调用几个外部二进制文件/命令,这些二进制文件/命令不能很好地终止。它们在后台并行并相互通信。
但是,我的脚本 C 能够检测到外部命令何时完成它们的工作,即使它们没有终止,然后我的 bash 脚本退出。
为了在 bash 脚本完成期间终止所有外部程序,我添加了一个退出陷阱:
# Exit cleanup
cleanup_exit() {
# Running the termination in an own process group to prevent it from preliminary termination. Since it will run in the background it will not cause any delays
setsid nohup bash -c "
touch /tmp/trace_1 # To see if this code was really executed to this point
# Trapping signals to prevent that this function is terminated preliminary
trap '' SIGINT SIGQUIT SIGTERM SIGHUP ERR
touch /tmp/trace_2 # To see if this code was really executed to this point
# Terminating the main processes
kill ${pids[@]} 1>/dev/null 2>&1 || true
touch /tmp/trace_3
sleep 5
touch /tmp/trace_4
kill -9 ${pids[@]} 1>/dev/null 2>&1 || true
touch /tmp/trace_5
# Terminating the child processes of the main processes
echo "Terminating the child processes"
pkill -P ${pids[@]} 1>/dev/null 2>&1 || true
touch /tmp/trace_6
sleep 1
pkill -9 -P ${pids[@]} 1>/dev/null 2>&1 || true
touch /tmp/trace_7
# Terminating everything else which is still running and which was started by this script
pkill -P $$ || true
touch /tmp/trace_8
sleep 1
pkill -9 -P $$ || true
touch /tmp/trace_9
"
}
trap "cleanup_exit" SIGINT SIGQUIT SIGTERM EXIT
现在,如果我只并行运行很少的脚本 C 实例,这似乎可行。如果我将数字增加到更多,例如10(工作站功能强大,应该可以并行处理几十个脚本C和外部程序的并行实例),然后就不行了,外部程序的数百个实例正在快速积累。
但是我不明白为什么。例如,累积的其中一个进程的 PID 是 32048。在日志中我可以看到退出陷阱的执行:
+ echo ' * Snapshot 190 completed after 3 seconds.'
* Snapshot 190 completed after 3 seconds.
+ break
+ cleanup_exit
+ echo
+ echo ' * Cleaning up...'
* Cleaning up...
+ setsid nohup bash -c '
touch /tmp/trace_1 # To see if this code was really executed to this point
# Trapping signals to prevent that this function is terminated preliminary
trap '\'''\'' SIGINT SIGQUIT SIGTERM SIGHUP ERR
touch /tmp/trace_2 # To see if this code was really executed to this point
# Terminating the main processes
kill 31678' '32048 1>/dev/null 2>&1 || true
touch /tmp/trace_3
sleep 5
touch /tmp/trace_4
kill -9 31678' '32048 1>/dev/null 2>&1 || true
touch /tmp/trace_5
# Terminating the child processes of the main processes
pkill -P 31678' '32048 1>/dev/null 2>&1 || true
touch /tmp/trace_6
sleep 1
pkill -9 -P 31678' '32048 1>/dev/null 2>&1 || true
touch /tmp/trace_7
# Terminating everything else which is still running and which was started by this script
pkill -P 31623 || true
touch /tmp/trace_8
sleep 1
pkill -9 -P 31623 || true
touch /tmp/trace_9
'
很明显,exit trap中使用了这个进程的PID,但是进程并没有退出。为了测试,我在此进程上再次手动运行 kill 命令,然后它确实退出了。
最有趣的是,只出现了直到编号 5 的跟踪文件。没有超过 5,但为什么呢?
更新:我刚刚发现,即使我只并行运行脚本 C 的一个实例,即顺序运行,它也只能在一段时间内运行良好。突然在某个时间点进程不再终止,而是开始永远徘徊并积累。机器不应因并行的一个过程而重载。在我的日志文件中,退出陷阱仍然像以前一样正确调用,没有区别。内存也是免费的,CPU 也是部分免费的。
最佳答案
对任何 shell 脚本进行健全性检查的一个很好的方法是在其上运行 ShellCheck:
Line 9:
kill ${pids[@]} 1>/dev/null 2>&1 || true
^-- SC2145: Argument mixes string and array. Use * or separate argument.
确实,您的 xtrace 在这一行做了一些奇怪的事情:
kill 31678' '32048 1>/dev/null 2>&1 || true
^^^--- What is this?
这里的问题是你的 ${pids[@]}
扩展成多个单词,而 bash -c
只解释第一个单词。这是一个简化的示例:
pids=(2 3 4)
bash -c "echo killing ${pids[@]}"
这最终写成killing 2
,没有提到3或4。相当于运行
bash -c "echo killing 2" "3" "4"
其他 pid 只是成为位置参数 $0
和 $1
而不是已执行命令的一部分。
相反,喜欢 ShellCheck suggested ,您希望 *
将所有 pids 与空格连接起来并将它们作为单个参数插入:
pids=(2 3 4)
bash -c "echo killing ${pids[*]}"
打印killing 2 3 4
。
关于linux - 杀死由 Bash 脚本启动的所有进程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46513568/
如何在终止父进程时关闭我的子文件描述符? 我创建了一个执行以下操作的程序: 派生 2 个子进程。 进程 1 是一个读取器。它从 STDIN_FILENO 读取并使用 scanf/printf 写入 S
我试着写了一个小的暴力破解程序。密码程序在密码正确时返回 1,错误时返回 0。所以它很简单。 在 bruteforce 程序中,我使用 createprocess() 调用 pw 程序。 我的问题是,
谁能帮我解释一下我从一本书中得到的这个脚本。练习是编写一个名为 killalljobs 的脚本来终止所有后台作业。 为此给出的代码是: kill "$@" $( jobs -p) 我确定我在这里真
我正在开发一个包含许多库的应用程序。后来我注意到有几次应用程序进程在关闭应用程序后仍在耗尽 CPU。 我先终止了进程,但它继续运行。我卸载了该应用程序 - 但它仍然存在! (使用开发人员选项中的“显示
有没有办法在无人机完成或超时之前杀死它? 无人机的默认超时时间为 6 小时 ( https://github.com/drone/drone/blob/master/cmd/drone/drone.g
我有几个自动启动的菜单栏程序/进程/应用程序。我希望能够使用单个命令或脚本将它们全部关闭;有时带宽受到限制或受限,它们会导致(或至少导致)旋转的沙滩球死亡。目前,我手动关闭每一个。 关注 answer
当我阅读 learnyousomeerlang.com 上的一篇文章时,我有一个问题。 http://learnyousomeerlang.com/errors-and-processes 它说: E
有什么方法可以通过 OpenCL API 终止正在运行的 OpenCL 内核吗?我没有在规范中找到任何内容。 我能想出的唯一解决方案是 1) 定期检查内核中的标志,当主机希望内核停止时写入该标志,或
我已经对套接字(使用fsockopen()和stream_socket_client())和cURL进行了一些测试,以强制关闭连接(TCP/HTTP)。但是,没有运气。 无论我使用的是1毫秒的超时时间
已关闭。这个问题是 off-topic 。目前不接受答案。 想要改进这个问题吗? Update the question所以它是on-topic用于堆栈溢出。 已关闭10 年前。 Improve th
我以不太优雅的方式杀死了 IRB 提示符(从 heroku run irb 开始),现在我有一个僵尸进程,但我似乎无法杀死它: Process State Co
致kill background process inside Codeship我们需要使用以下命令: #!/bin/bash nohup bash -c "YOUR_COMMAND 2>&1 &"
我第一次在这里发帖,因为我在互联网上找不到干净的解决方案。 我的目标很简单,我需要创建 一个 后台操作 (goroutine 或进程或其他...)我可以 正确杀死 (不要留在后台)。 我尝试了很多事情
我有一个进程调用: p=multiprocessing.Process(target=func_a) 然后func_a启动一个子进程: subprocess.Popen(["nc", "-l", "-
我正在运行一个基本上运行一堆服务器以进行本地测试的脚本。 这些 jar 在不同的 screen 中运行,因为它们需要独立地接受键盘输入。为此,我使用了 screen 。 command1="java
我有一个用 java 编写的应用程序,它在 Unix 上运行,并在启动时启动两个子进程(通过 Runtime.getRuntime().exec())。如果应用程序由于某种原因崩溃,子进程不会被终止。
我想要像 Pushbullet、SmartLockScreen 或 WhatsApp 那样独立运行的服务,它正在等待某个事件的发生。我已经尝试过前台服务,在 onStartCommand 中返回 ST
强制停止应用程序后,是否可以在 Android 应用程序中获取位置更新。在 IOS 中,如果我们强制停止应用程序,则有可能获得位置更新,以类似的方式,是否有任何服务可以为在 android 中被杀死的
我正在调查是否有任何方法可以防止 android 服务因未捕获的异常而被杀死。 我们有 10 个 UI 应用程序与 5-6 个服务通信。该平台是Android 2.2。 由于不可预见的情况,服务中的某
我刚刚将我的 javascript 转移到 jQuery 来实现简单的 AJAX 功能。不过,我尝试将灯箱插件与 jQuery 结合使用,因为我想保留相同的功能,但不想包含 10 个不同的库。如果我删
我是一名优秀的程序员,十分优秀!