Go语言使用exec包运行REST API二进制程序时如何实现运行期打印操作
Go 启动外部子进程时实现并行执行的方法
问题出现的根本原因
你现在的执行顺序问题,本质是cmd.Run()的设计特性导致的:这个方法是同步阻塞调用,它会先启动指定的二进制程序,然后一直挂起当前主程序的执行流程,直到这个二进制进程完全退出、所有关联的IO流全部回收完毕,才会把执行权交还给主程序。
这就解释了为什么你的fmt.Println("A")必须等手动停掉REST API进程才会执行——它根本没机会在子进程运行的时候被调用。
对应修改方案
用非阻塞启动方法替换原有的Run调用
Go标准库的os/exec包提供了Start()方法,这个方法只会完成子进程的启动动作,不会等待进程退出,调用完成后会立刻返回让主程序继续向下执行:
cmd = exec.Command("./app-godemon-app-godemon-tmp-generated") cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr // 替换原来的cmd.Run()为Start调用 if err := cmd.Start(); err != nil { log.Fatalf("子进程启动失败: %v", err) } // 这行代码现在会在REST API启动完成后立刻执行,不需要等进程退出 fmt.Println("A")
注意:如果只调用
Start()而不做后续处理,当主程序自身执行完所有逻辑退出时,已经启动的子进程也会被系统连带终止。如果你需要让主程序和子进程保持同生命周期(也就是API不退出、主程序也跟着不退出),只需要把原来的阻塞等待逻辑挪到所有并行执行的代码后面即可:在所有需要和API并行运行的逻辑写完之后,再调用
cmd.Wait()方法挂起主程序。这个方法同样会阻塞等待子进程退出,但因为你要提前执行的打印、其他并行任务都已经放在它之前了,完全不会影响你的需求。
调整后的完整基础结构参考:
cmd = exec.Command("./app-godemon-app-godemon-tmp-generated") cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Start(); err != nil { log.Fatalf("子进程启动失败: %v", err) } // 这里开始所有需要和REST API并行运行的逻辑 fmt.Println("A") // 可以插入其他逻辑:比如启动定时健康检查、接收控制台控制指令、打印服务运行状态等 // 所有并行逻辑启动完成后,再阻塞等待子进程退出,防止主程序直接结束 if err := cmd.Wait(); err != nil { log.Printf("子进程退出异常: %v", err) }
运行过程中持续打印的常见用法
如果你需要在REST API全程运行的过程中定期打印内容,只需要在主逻辑里启动协程配合定时器即可:
// 接上面的Start调用、打印"A"的逻辑 go func() { ticker := time.NewTicker(10 * time.Second) defer ticker.Stop() for range ticker.C { fmt.Println("8000端口的REST API当前仍在正常运行") } }() // 最后等待子进程退出 cmd.Wait()
内容的提问来源于stack exchange,提问作者norbert wagner
相关产品推荐
相关产品推荐

