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

黔东网站建设app开发外包服务

黔东网站建设,app开发外包服务,wordpress评论表单,网络营销的特征简介#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.pierceye.com/news/601344/

相关文章:

  • 公司网站用什么开发网站 建设 计划书
  • 安陆市城乡建设局网站w10怎么做信任网站
  • wordpress上站工具内网门户网站
  • 商城网站服务器漳浦建设银行网站
  • 可视化 网站开发工具音乐网站后台管理模板
  • 网站架构功能模块及描述网站聊天怎么做
  • 京东电子商务网站的建设做网站运营需要什么资源
  • 市北建筑建网站哪家好个体户可以做网站吗
  • 怎么建自己的网站?网站优化包括哪些内容
  • 网站后台登录域名国外网站网站app
  • 山西建设工程协会网站wordpress二次元主题个人
  • 加强人社局网站建设获取小程序api
  • 服务器网站备案学生ppt模板免费下载 素材
  • 手机做网站软件运营管理培训
  • 迅博威网站建设南宁 建网站 公司
  • 河北省建设机械协会是正规网站吗网站及网页设计费用
  • 门户网站seo前期铁岭网站建设移动网站
  • 肇庆免费模板建站jsp电商网站开发流程图
  • 阿里巴巴国际站网站建设青岛网站搭建公司哪家好
  • 能看人与动物做的网站浙江企业响应式网站建设设计
  • 乌兰察布做网站公司营销策划公司有哪些职位
  • 南宁区建设银行招聘网站建设部网站申请表无法打印
  • 建一个网站怎么赚钱吗家具网站源码
  • 云优化网站建设wordpress开启icon
  • 招聘网站开发的目的与意义农特产品电商网站建设目标
  • 三水 网站建设公司企业黄页
  • 网站建设公司词辽宁阜新建设学校官方网站
  • 广州公司网站建设设计顾视频网站的建设预算
  • 商务网站规划与网页制作seo优化内容
  • 石家庄网站定做公众号开发单位