Golang中如何避免误杀由Go启动的Linux进程
Golang中如何避免误杀由Go启动的Linux进程 我需要从Go管理的HTML站点控制数据库和其他消息服务器。我可以启动这些进程,但它们会随着Go管理的HTML服务器一起结束。有没有办法让Go启动的进程在启动它们的Go例程结束(或崩溃)后继续存活?
谢谢,它起作用了!Process.Release() 是一个隐藏得很深的函数,还是我在做梦?我认为这正是我需要的,再次感谢。
更多关于Golang中如何避免误杀由Go启动的Linux进程的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
你需要释放子进程。
cmd := exec.Command(binary, args...)
cmd.Dir = cwd
err = cmd.Start()
if err != nil {
return err
}
err = cmd.Process.Release()
你所说的“go启动的进程”是什么意思?你指的是goroutine吗?就像go的html网站(服务器)启动一个goroutine来控制数据库,再启动另一个goroutine来处理消息传递?我不确定这是否可行,因为据我所知,当创建它们的主goroutine结束时,所有goroutine都会结束。
但如果你指的是启动的外部程序,我认为有exec.Start()可以用于此目的。
你可以做的是将这些goroutine转变为独立的程序/服务,并让它们能够从你的(html)Web服务器接收消息/指令。
是的,这正是我的意思。更具体地说,我有一个模拟物联网设备数据传输的 Go 程序。我希望能够从一个 HTML 页面(即正在运行的 Go 服务器)来控制这个程序。使用 exec.Start() 效果很好,但如果 HTML 服务器停止,我的物联网模拟器也会停止,这并不理想。我需要的是一个能创建新进程然后让其完全独立运行的过程。
我尝试过使用 StartProcess,但似乎由 Go 程序创建的每个进程实际上都是主程序的子进程。
func main() {
fmt.Println("hello world")
}
更正:我无法让 cmd.Process.Release 正常工作。
有效的方法是:在 Go 代码中,使用 nohup 和 & 启动子进程。从终端启动我的服务器,而不是从 Goland IDE。似乎 IDE 会让 Go 程序在一个父进程 ___go_build_main_go 下运行,该进程会强制终止所有子进程。如果我没理解错的话,nohup 和 & 的作用是将进程与终端应用程序分离。我将在没有运行 Xorg 的 Linux 系统上测试它。通常,当一个进程变成孤儿进程时,它不会被杀死,而是会以一个相近的 PID 作为父进程(在正常情况下是 init),所以这个问题本不应该被提出。
在Go中启动独立于父进程的Linux进程,可以使用syscall.SysProcAttr设置进程属性。关键是将进程设置为新的进程组领导,并确保父进程退出时子进程不被终止。
以下是实现方式:
package main
import (
"log"
"os"
"os/exec"
"syscall"
)
func startDetachedProcess(command string, args ...string) (*os.Process, error) {
cmd := exec.Command(command, args...)
// 设置进程属性
cmd.SysProcAttr = &syscall.SysProcAttr{
// 创建新的进程组
Setpgid: true,
// 可选的:设置子进程在父进程退出后不会被终止
Pgid: 0,
}
// 重定向标准输入输出(可选)
cmd.Stdin = nil
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
// 启动进程
if err := cmd.Start(); err != nil {
return nil, err
}
// 立即释放资源,不等待进程结束
go func() {
cmd.Wait()
}()
return cmd.Process, nil
}
func main() {
// 示例:启动一个独立的数据库进程
proc, err := startDetachedProcess("redis-server", "--port", "6379")
if err != nil {
log.Fatal("启动进程失败:", err)
}
log.Printf("已启动独立进程,PID: %d\n", proc.Pid)
// Go程序可以安全退出,子进程会继续运行
// 即使Go程序崩溃,子进程也不会被终止
}
更彻底的分离可以使用双重fork技术:
func startFullyDetached(command string, args ...string) error {
attr := &syscall.SysProcAttr{
Setsid: true, // 创建新的会话
}
// 第一次fork
pid, _, errno := syscall.RawSyscall(syscall.SYS_FORK, 0, 0, 0)
if errno != 0 {
return errno
}
if pid > 0 {
// 父进程直接退出
os.Exit(0)
}
// 子进程继续执行
syscall.Setsid()
// 第二次fork
pid2, _, errno := syscall.RawSyscall(syscall.SYS_FORK, 0, 0, 0)
if errno != 0 {
os.Exit(1)
}
if pid2 > 0 {
os.Exit(0)
}
// 最终的子进程执行目标命令
syscall.Exec(command, args, os.Environ())
return nil
}
对于需要管理多个后台进程的场景,可以考虑使用systemd或supervisor等进程管理工具,Go程序只需通过systemd API或配置文件来管理这些服务。

