当前位置: 首页 > news >正文

郑州做花店网站宣传彩页设计制作

郑州做花店网站,宣传彩页设计制作,2022年大连黄页,我的专业网站建设策划书简介#xff1a; 在 Go 程序当中#xff0c;如果我们要执行命令时#xff0c;通常会使用 exec.Command #xff0c;也比较好用#xff0c;通常状况下#xff0c;可以达到我们的目的#xff0c;如果我们逻辑当中#xff0c;需要终止这个进程#xff0c;则可以快速使用 …简介 在 Go 程序当中如果我们要执行命令时通常会使用 exec.Command 也比较好用通常状况下可以达到我们的目的如果我们逻辑当中需要终止这个进程则可以快速使用 cmd.Process.Kill() 方法来结束进程。但当我们要执行的命令会启动其他子进程来操作的时候会发生什么情况 作者 | 昕希 来源 | 阿里技术公众号 在 Go 程序当中如果我们要执行命令时通常会使用 exec.Command 也比较好用通常状况下可以达到我们的目的如果我们逻辑当中需要终止这个进程则可以快速使用 cmd.Process.Kill() 方法来结束进程。但当我们要执行的命令会启动其他子进程来操作的时候会发生什么情况 一 孤儿进程的产生 测试小程序 func kill(cmd *exec.Cmd) func() {return func() {if cmd ! nil {cmd.Process.Kill()}} }func main() {cmd : exec.Command(/bin/bash, -c, watch top top.log)time.AfterFunc(1*time.Second, kill(cmd))err : cmd.Run()fmt.Printf(pid%d err%s\n, cmd.Process.Pid, err) } 执行小程序 go run main.gopid27326 errsignal: killed 查看进程信息 ps -jUSER PID PPID PGID SESS JOBC STAT TT TIME COMMAND king 24324 1 24303 0 0 S s012 0:00.01 watch top 可以看到这个 watch top 的 PPID 为 1说明这个进程已经变成了 “孤儿” 进程。 那为什么会这样这并不符合我们预期那么可以从 Go 的文档中找到答案 二 通过进程组来解决掉所有子进程 在 linux 当中是有会话、进程组和进程组的概念并且 Go 也是使用 linux 的 kill(2) 方法来发送信号的那么是否可以通过 kill 来将要结束进程的子进程都结束掉 linux 的 kill(2) 的定义如下 并在方法的描述中可以看到如下内容 如果 pid 为正数的时候会给指定的 pid 发送 sig 信号如果 pid 为负数的时候会给这个进程组发送 sig 信号那么我们可以通过进程组来将所有子进程退出掉改一下 Go 程序中 kill 方法 func kill(cmd *exec.Cmd) func() {return func() {if cmd ! nil {// cmd.Process.Kill()syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL)}} }func main() {cmd : exec.Command(/bin/bash, -c, watch top top.log)time.AfterFunc(1*time.Second, kill(cmd))err : cmd.Run()fmt.Printf(pid%d err%s\n, cmd.Process.Pid, err) } 再次执行 go run main.go 会发现程序卡住了我们来看一下当前执行的进程 ps -jUSER PID PPID PGID SESS JOBC STAT TT TIME COMMAND king 27655 91597 27655 0 1 S s012 0:01.10 go run main.go king 27672 27655 27655 0 1 S s012 0:00.03 ..../exe/main king 27673 27672 27655 0 1 S s012 0:00.00 /bin/bash -c watch top top.log king 27674 27673 27655 0 1 S s012 0:00.01 watch top 可以看到我们 go run 产生了一个子进程 27672command 那里是 go 执行的临时目录比较长因此添加了省略号27672 产生了 27673watch top top.log进程27673 产生了 27674watch top进程。那为什么没有将这些子进程都关闭掉呢 其实之类犯了一个低级错误从上图中我们可以看到他们的进程组 ID 为 27655但是我们传递的是 cmd 的 id 即 27673这个并不是进程组的 ID因此程序并没有 kill导致 cmd.Run() 一直在执行。 在 Linux 中进程组中的第一个进程被称为进程组 Leader同时这个进程组的 ID 就是这个进程的 ID从这个进程中创建的其他进程都会继承这个进程的进程组和会话信息从上面可以看出 go run main.go 程序 PID 和 PGID 同为 27655那么这个进程就是进程组 Leader我们不能 kill 这个进程组除非想“自杀”哈哈哈。 那么我们给要执行的进程新建一个进程组在 Kill 不就可以了嘛。在 linux 当中通过 setpgid 方法来设置进程组 ID定义如下 如果将 pid 和 pgid 同时设置成 0也就是 setpgid(0,0)则会使用当前进程为进程组 leader 并创建新的进程组。 那么在 Go 程序中可以通过 cmd.SysProcAttr 来设置创建新的进程组修改后的代码如下 func kill(cmd *exec.Cmd) func() {return func() {if cmd ! nil {// cmd.Process.Kill()syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL)}} }func main() {cmd : exec.Command(/bin/bash, -c, watch top top.log)cmd.SysProcAttr syscall.SysProcAttr{Setpgid: true,}time.AfterFunc(1*time.Second, kill(cmd))err : cmd.Run()fmt.Printf(pid%d err%s\n, cmd.Process.Pid, err) } 再次执行 go run main.gopid29397 errsignal: killed 再次查看进程 ps -jUSER PID PPID PGID SESS JOBC STAT TT TIME COMMAND 发现 watch 的进程都不存在了那我们在看看是否还会有孤儿进程 # 由于我测试的环境是mac因此这个脚本只能在mac执行 ps -j | head -1;ps -j | awk {if ($3 1 $1 !root){print $0}} | headUSER PID PPID PGID SESS JOBC STAT TT TIME COMMAND 已经没有孤儿进程了问题至此已经完全解决。 三 子进程监听父进程是否退出(只能在 linux 下执行) 假设要调用的程序也是我们自己写的其他应用程序那么可以使用 Linux 的 prctl 方法来处理 prctl 方法的定义如下 这个方法有一个重要的 optionPR_SET_PDEATHSIG通过这个来接收父进程的退出。 让我们来再次构造一个有问题的程序。 有两个文件分别为 main.go 和 child.go 文件main.go 会调用 child.go 文件。 main.go 文件 package mainimport (os/exec )func main() {cmd : exec.Command(./child)cmd.Run() } child.go 文件 package mainimport (fmttime )func main() {for {time.Sleep(200 * time.Millisecond)fmt.Println(time.Now())} } 在 Linux 环境中分别编译这两个文件 // 编译 main.go 生成 main 二进制文件 go build -o main main.go// 编译 child.go 生成 child 二进制文件 go build -o child child.go 执行 main 二进制文件 ./main 查看他们的进程 ps -efUID PID PPID C STIME TTY TIME CMD root 1 0 0 06:05 pts/0 00:00:00 /bin/bash root 11514 1 0 12:12 pts/0 00:00:00 ./main root 11520 11514 0 12:12 pts/0 00:00:00 ./child 可以看到 main 和 child 的进程child 是 main 的子进程我们将 main 进程 kill 掉在查看进程状态 kill -9 11514ps -efUID PID PPID C STIME TTY TIME CMD root 1 0 0 06:05 pts/0 00:00:00 /bin/bash root 11520 1 0 12:12 pts/0 00:00:00 ./child 我们可以看到 child 的进程他的 PPID 已经变成了 1说明这个进程已经变成了孤儿进程。 那接下来我们可以使用 PR_SET_PDEATHSIG 来保证父进程退出子进程也退出大致方式有两种使用 CGO 调用和使用 syscall.RawSyscall 来调用。 1 使用 CGO 将 child 修改成如下内容 程序中使用 CGO为了简单的展示在 Go 文件中编写了 C 的 killTest 方法并调用了 prctl 方法然后在 Go 程序中调用 killTest 方法让我们重新编译执行一下再看看进程 go build -o child child.go ./main ps -ef UID PID PPID C STIME TTY TIME CMD root 1 0 0 06:05 pts/0 00:00:00 /bin/bash root 11663 1 0 12:28 pts/0 00:00:00 ./main root 11669 11663 0 12:28 pts/0 00:00:00 ./child 再次 kill 掉 main并查看进程 kill -9 11663 ps -efUID PID PPID C STIME TTY TIME CMD root 1 0 0 06:05 pts/0 00:00:00 /bin/bash 可以看到 child 的进程也已经退出了说明 CGO 调用的 prctl 生效了。 2 syscall.RawSyscall 方法 也可以采用 Go 中提供的 syscall.RawSyscall 方法来替代调用 CGO在 Go 的文档中可以查看到 syscall 包中定义的常量查看 linux如果是本地 godoc需要指定 GOOSlinux可以看到我们要用的几个常量以及他们对应的数值 // 其他内容省略掉了 const(....PR_SET_PDEATHSIG 0x1.... )const( .....SYS_PRCTL 157..... ) 其中 PR_SET_PDEATHSIG 操作的值为 1SYS_PRCTL 的值为 157那么将 child.go 修改成如下内容 package mainimport (fmtossyscalltime )func main() {_, _, errno : syscall.RawSyscall(uintptr(syscall.SYS_PRCTL), uintptr(syscall.PR_SET_PDEATHSIG), uintptr(syscall.SIGKILL), 0)if errno ! 0 {os.Exit(int(errno))}for {time.Sleep(200 * time.Millisecond)fmt.Println(time.Now())} } 再次编译并执行 go build -o child child.go ./main ps -efUID PID PPID C STIME TTY TIME CMD root 1 0 0 06:05 pts/0 00:00:00 /bin/bash root 12208 1 0 12:46 pts/0 00:00:00 ./main root 12214 12208 0 12:46 pts/0 00:00:00 ./child 将 main 进程结束掉 kill -9 12208 ps -efUID PID PPID C STIME TTY TIME CMD root 1 0 0 06:05 pts/0 00:00:00 /bin/bash child 进程已经退出了也达成了最终效果。 四 总结 当我们使用 Go 程序执行其他程序的时候如果其他程序也开启了其他进程那么在 kill 的时候可能会把这些进程变成孤儿进程一直执行并滞留在内存中。当然如果我们程序非法退出或者被 kill 调用也会导致我们执行的进程变成孤儿进程那么为了解决这个问题从两个思路来解决 给要执行的程序创建新的进程组并调用 syscall.Kill传递负值 pid 来关闭这个进程组中所有的进程比较完美的解决方法。如果要调用的程序也是我们自己编写的那么可以使用 PR_SET_PDEATHSIG 来感知父进程退出那么这种方式需要调用 Linxu 的 prctrl可以使用 CGO 的方式也可以使用 syscall.RawSyscall 的方式。 但不管使用哪种方式都只是提供了一种思路在我们编写服务端服务程序的时候需要特殊关注防止孤儿进程消耗服务器资源。 原文链接 本文为阿里云原创内容未经允许不得转载。
http://www.sadfv.cn/news/231796/

相关文章:

  • 1000学习做网站贵吗公司的logo图片
  • 国外网站设计参考经营虚拟网站策划书
  • 北京展示型网站如何把网站上传到网上
  • 不会编程如何做自己的网站线上营销模式
  • 简单的做网站软件有啥无法打开网页是怎么回事
  • 二级域名对于英文网站推广有什么影响网站优化分析软件
  • 网站设计的公司logo锐旗 天梯网站建设
  • 无锡电商网站设计毕业答辩ppt模板免费下载网站
  • 网站建设费用怎么核算代理网关app未运行
  • 专业做网站企业网站做数据分析的意义
  • 做网站注册商标简单的手机网站模板下载
  • 徐州集团网站建设流程2021年国家大事件有哪些
  • 安钢贴吧论坛沧州网站推广优化商集客电话
  • 网站管理员后台广州购物网站公司地址
  • 做网站能用本地的数据库嘛门户网站建设及运营
  • 大连建站软件专业网站建设费用
  • 公司宣传网站在环评备案网站上做登记后会怎么样6
  • html模板网站模板下载天津西青建设工程网站
  • 怎么诊断网站企业网站优化设计的含义
  • 网站开发培训哪里好网站内容建设
  • 彩虹云商城网站搭建互联网创业项目代理
  • windows设置wordpress网站建设快照优化
  • 企业网站源码变现方法网站开发如何共用菜单栏
  • 根据 我司申请 网站建设平台网站 备案吗
  • 怎么做网站寄生虫毕设 做网站
  • 网站如何防止黑客攻击汕头建站网站模板
  • 南宁有做网站的公司吗何做百度推广网站
  • 哪个网站可以做自己的网页网站首页点击中文英文链接 翻译成对应的语言 怎么做
  • 龙岩有什么招聘本地网站wordpress搭建拒绝访问
  • 苏州做网站费用制作网页需要哪些技术