Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/go/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
终止在Golang中使用os/exec启动的进程_Go - Fatal编程技术网

终止在Golang中使用os/exec启动的进程

终止在Golang中使用os/exec启动的进程,go,Go,有没有办法终止在Golang中使用os.exec启动的进程?例如(来自), 有没有办法提前终止这个过程,也许是在3秒钟之后 提前感谢终止正在运行的执行进程: // Start a process: cmd := exec.Command("sleep", "5") if err := cmd.Start(); err != nil { log.Fatal(err) } // Kill it: if err := cmd.Process.Kill(); err != nil {

有没有办法终止在Golang中使用os.exec启动的进程?例如(来自),

有没有办法提前终止这个过程,也许是在3秒钟之后


提前感谢

终止正在运行的
执行进程

// Start a process:
cmd := exec.Command("sleep", "5")
if err := cmd.Start(); err != nil {
    log.Fatal(err)
}

// Kill it:
if err := cmd.Process.Kill(); err != nil {
    log.Fatal("failed to kill process: ", err)
}

超时后终止正在运行的执行进程:

// Start a process:
cmd := exec.Command("sleep", "5")
if err := cmd.Start(); err != nil {
    log.Fatal(err)
}

// Wait for the process to finish or kill it after a timeout (whichever happens first):
done := make(chan error, 1)
go func() {
    done <- cmd.Wait()
}()
select {
case <-time.After(3 * time.Second):
    if err := cmd.Process.Kill(); err != nil {
        log.Fatal("failed to kill process: ", err)
    }
    log.Println("process killed as timeout reached")
case err := <-done:
    if err != nil {
        log.Fatalf("process finished with error = %v", err)
    }
    log.Print("process finished successfully")
}
//启动一个进程:
cmd:=exec.Command(“sleep”,“5”)
如果错误:=cmd.Start();呃!=零{
log.Fatal(错误)
}
//等待进程完成或在超时后终止(以先发生的为准):
完成:=生成(chan错误,1)
go func(){

完成没有选择和通道的简单版本

func main() {
    cmd := exec.Command("cat", "/dev/urandom")
    cmd.Start()
    timer := time.AfterFunc(1*time.Second, func() {
        err := cmd.Process.Kill()
        if err != nil {
            panic(err) // panic as can't kill a process.
        }
    })
    err := cmd.Wait()
    timer.Stop()

    // read error from here, you will notice the kill from the 
    fmt.Println(err)
}
好吧,在咨询了一些有经验的围棋程序员之后,这显然不是一个解决问题的好办法。所以请参考公认的答案


这是一个更短的版本,非常简单。但是,如果超时时间长,可能会有大量挂起的goroutine

func main() {
    cmd := exec.Command("cat", "/dev/urandom")
    cmd.Start()
    go func(){
        time.Sleep(timeout)
        cmd.Process.Kill()
    }()
    return cmd.Wait()
}

关于调用
Kill()
,其他答案是正确的,但是关于在超时后终止进程的部分现在已经过时了

现在可以使用
上下文
包和(根据文档中的示例改编的示例)完成此操作:

从文档中:

func main() {
    ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
    defer cancel()

    if err := exec.CommandContext(ctx, "sleep", "5").Run(); err != nil {
        // This will fail after 100 milliseconds. The 5 second sleep
        // will be interrupted.
    }
}
如果上下文在命令自行完成之前完成,则提供的上下文用于终止进程(通过调用os.process.kill)


Run()
完成后,您可以检查
ctx.Err()
。如果达到超时,返回的错误类型将为。如果是
nil
,请检查
Run()
返回的
Err
以查看命令是否在没有错误的情况下完成。

注意:终止进程后,请等待()将返回。您应该在
err:=cmd.Process.Kill()
之后从“完成”执行拉取操作,以防止内存泄漏。@RhythmaticFistman它将导致goroutine挂起,直到程序试图发送到“完成”时,没有人收到它。更好的方法是将第一行更改为
done:=make(chan error,1)
。这将允许发送立即成功,并且goroutine在未完成拉入操作的情况下退出。@CharlieParker,这将确保发送到频道的一次发送始终会立即成功,发送者可以继续发送,或者在本例中可以退出。如果不成功,它将等待有人接收。如果没有人这样做,它将永远等待并保持不变内存。@KamilDziedzic,写入完成的目的是确保程序已退出(等待返回)在继续执行程序之前。在任何情况下,程序都不能在select语句之后继续运行。如果您执行非阻塞写入,则不会得到保证。@StephenWeinberg我不明白。它的等待方式与
cmd.Wait()
上的原始代码完全相同,只有当a)缓冲区已满时,写入完成可能才会失败(它在发送第一个值后具有)b)没有等待接收的内容…实际上这意味着goroutine可能会在主goroutine准备接收之前尝试发送到完成…所以,是的,需要缓冲chan。但我仍然不明白为什么你说它不会等待cmd完成
func main() {
    ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
    defer cancel()

    if err := exec.CommandContext(ctx, "sleep", "5").Run(); err != nil {
        // This will fail after 100 milliseconds. The 5 second sleep
        // will be interrupted.
    }
}