等到条件满足或超时

时间:2018-07-14 12:45:03

标签: go

在这种情况下,我试图编写一个在满足条件时会中断的函数,命令的输出等于某个值(在此示例中为hello),或者 超时

timeout := 10 sec

func run() error {

for {

    out , _ := exec.Command("echo", "hello").Output()
    if string(out) == "hello" || timeout  {
        break
    }
}

}

我已经看到人们使用select,但是我不知道如何在其中使用它, 有什么提示吗?

2 个答案:

答案 0 :(得分:6)

如果命令运行迅速,则可以使用以下简单方法:

deadline := time.Now().Add(10 * time.Second)
for {
    out, _ := exec.Command("echo", "hello").Output()
    if string(out) == "hello" || time.Now().After(deadline) {
        break
    }
}

一种改进是使用context with a timeout

ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
for {
    out, _ := exec.CommandContext(ctx, "echo", "hello").Output()
    if string(out) == "hello" || ctx.Err() != nil {
        break
    }
}

上下文版本将在超时时终止命令。代码将循环直到找到字符串或the context is done

答案 1 :(得分:3)

您可以使用类似于Go by Example: Timeouts

的代码
c2 := make(chan string, 1) 
go func() {
    time.Sleep(2 * time.Second)
    c2 <- "result 2"
}()
select {
case res := <-c2:
    fmt.Println(res)
case <-time.After(3 * time.Second):
    fmt.Println("timeout 2")
}

在您的情况下,go funcexec echo,而main函数将等待超时或go func的执行,以先到者为准。

即:https://goplay.space/#MtHh3CenMcn

package main

import (
    "fmt"
    "os/exec"
    "time"
)

func main() {
    c2 := make(chan string, 1)
    go func() {
        out, err := exec.Command("echo", "hello").Output()
        fmt.Println(err)
        c2 <- string(out)
    }()
    select {
    case res := <-c2:
        fmt.Println("'" + res + "'")
    case <-time.After(3 * time.Second):
        fmt.Println("timeout 2")
    }
}

如果echo花费3秒钟以上,超时就会开始。

请注意,该示例不适用于游乐场设置,因为:

"echo": executable file not found in $PATH

但是在您的本地环境中,它应该可以工作。


基于上下文的另一种方法:https://goplay.space/#F2GtMLgVAAI

package main

import (
    "context"
    "fmt"
    "os/exec"
)

func main() {
    gen := func(ctx context.Context) <-chan string {
        dst := make(chan string)
        go func() {
            out, err := exec.Command("echo", "hello").Output()
            fmt.Println(err)
            for {
                select {
                case <-ctx.Done():
                    return // returning not to leak the goroutine
                case dst <- string(out):
                    return
                }
            }
        }()
        return dst
    }

    ctx, cancel := context.WithTimeout(context.Background(), 3)

    defer cancel() // cancel when we are finished consuming integers
    gen(ctx)
}