Problem:
Sie möchten einen langen Befehl ausführen. Prozess in Golang ausführen und gleichzeitig mehrere Anforderungen erfüllen:
Lösungsversuch:
Sie haben versucht, eine Lösung mit exec.Command zu finden, diese erfüllt jedoch nicht alle Anforderungen, insbesondere wenn Ihr Programm SIGTERM/SIGKILL-Signale empfängt.
Wichtiger Punkt zum Verstehen:
Es ist wichtig zu beachten, dass Sie das übergeordnete Element eines Prozesses nicht mehr ändern können, sobald er gestartet wurde – die Eltern-Kind-Beziehung eines Prozesses ist festgelegt.
Alternative Bibliotheken:
Anstatt das Rad neu zu erfinden, empfiehlt es sich, eine vorhandene Bibliothek zu verwenden, die dieses Problem löst. Folgende Bibliotheken werden empfohlen:
Beispiel mit go-reap:
<code class="go">import ( "fmt" "os" "os/exec" "strings" "sync" "time" "github.com/fatih/color" "github.com/hashicorp/go-reap" ) func main() { if reap.IsSupported() { done := make(chan struct{}) var reapLock sync.RWMutex pids := make(reap.PidCh, 1) errors := make(reap.ErrorCh, 1) go reap.ReapChildren(pids, errors, done, &reapLock) go report(pids, errors, done) // Here is where you would start your long-running process Sh() close(done) } else { fmt.Println("Sorry, go-reap isn't supported on your platform.") } } func report(pids reap.PidCh, errors reap.ErrorCh, done chan struct{}) { sprintf := color.New(color.FgWhite, color.Bold).SprintfFunc() for ;; { select { case pid := <-pids: println(sprintf("raeper pid %d", pid)) case err := <-errors: println(sprintf("raeper er %s", err)) case <-done: return } } } func Sh() { args := os.Args[1:] script := args[0:0] if len(args) >= 1 { if args[0] == "-c" { script = args[1:] } } if len(script) == 0 { fn.CyanBold("cmd: expecting sh -c 'foobar'") os.Exit(111) } var cmd *exec.Cmd parts, _ := shlex.Split(strings.Join(script, " ")) if len(parts) >= 2 { cmd = fn.Merge(exec.Command(parts[0], parts[1:]...), nil) } if len(parts) == 1 { cmd = fn.Merge(exec.Command(parts[0]), nil) } // ... Here you can customize how the process is started and controlled if fn.IfEnv("HANG") { fn.CyanBold("cmd: %v\n start", parts) ex := cmd.Start() if ex != nil { fn.CyanBold("cmd %v err: %s", parts, ex) } go func() { time.Sleep(time.Millisecond * 100) errw := cmd.Wait() if errw != nil { fn.CyanBold("cmd %v err: %s", parts, errw) } else { fn.CyanBold("cmd %v all done.", parts) } }() fn.CyanBold("cmd: %v\n dispatched, hanging forever (i.e. to keep docker running)", parts) for { time.Sleep(time.Millisecond * time.Duration(fn.EnvInt("HANG", 2888))) fn.SystemCyan("/bin/ps", "-e", "-o", "stat,comm,user,etime,pid,ppid") } } else { if fn.IfEnv("NOWAIT") { ex := cmd.Start() if ex != nil { fn.CyanBold("cmd %v start err: %s", parts, ex) } } else { ex := cmd.Run() if ex != nil { fn.CyanBold("cmd %v run err: %s", parts, ex) } } fn.CyanBold("cmd %v\n dispatched, exit docker.", parts) } }</code>
Dieses Beispiel verwendet go-reap, um eine Shell zu starten (Sh()-Funktion) und einen Befehl innerhalb dieser Shell auszuführen. Es richtet den Reaper so ein, dass er die Bereinigung der untergeordneten Prozesse übernimmt.
Durch die Verwendung einer seriösen Bibliothek können Sie häufige Fallstricke vermeiden und sicherstellen, dass sich Ihre Anwendung wie beabsichtigt verhält.
Das obige ist der detaillierte Inhalt vonWie kann ich einen lang laufenden Prozess in Golang ausführen und ihn von meinem Programm trennen, während ich gleichzeitig den Benutzer kontrolliere, die Ausgabe umleite und verhindere, dass er zu einem Zombie wird?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!