如何暂停和恢复 goroutine?

Joh*_*ass 0 concurrency channel go goroutine

我正在尝试暂停和恢复 groutine。我知道我可以sleep跑步,但我正在寻找就像一个按钮“暂停/恢复”而不是一个计时器。

这是我的尝试。我正在使用通道的阻塞功能来暂停,并select根据通道值切换要执行的内容。但是,输出总是Running在我的情况下。

func main() {
    ctx := wctx{}
    go func(ctx wctx) {
        for {
            time.Sleep(1 * time.Second)
            select {
            case <-ctx.pause:
                fmt.Print("Paused")
                <-ctx.pause
            case <-ctx.resume:
                fmt.Print("Resumed")
            default:
                fmt.Print("Running \n")
            }
        }
    }(ctx)

    ctx.pause <- struct{}{}
    ctx.resume <- struct{}{}
}

type wctx struct {
    pause  chan struct{}
    resume chan struct{}
}
Run Code Online (Sandbox Code Playgroud)

icz*_*cza 5

select具有多个就绪案例的A伪随机地选择一个。因此,如果 goroutine 检查这些通道很“慢”,您可能会在两个pauseresume(假设它们已缓冲)上发送一个值,以便从两个通道接收可以准备好,并且resume可以首先选择,并在以后的迭代pause中goroutine 不应再暂停。

为此,您应该使用由互斥锁同步的“状态”变量。像这样的东西:

const (
    StateRunning = iota
    StatePaused
)

type wctx struct {
    mu    sync.Mutex
    state int
}

func (w *wctx) SetState(state int) {
    w.mu.Lock()
    defer w.mu.Unlock()
    w.state = state
}

func (w *wctx) State() int {
    w.mu.Lock()
    defer w.mu.Unlock()
    return w.state
}
Run Code Online (Sandbox Code Playgroud)

测试它:

ctx := &wctx{}
go func(ctx *wctx) {
    for {
        time.Sleep(1 * time.Millisecond)
        switch state := ctx.State(); state {
        case StatePaused:
            fmt.Println("Paused")
        default:
            fmt.Println("Running")
        }
    }
}(ctx)

time.Sleep(3 * time.Millisecond)
ctx.SetState(StatePaused)
time.Sleep(3 * time.Millisecond)
ctx.SetState(StateRunning)
time.Sleep(2 * time.Millisecond)
Run Code Online (Sandbox Code Playgroud)

输出(在Go Playground上试试):

Running
Running
Running
Paused
Paused
Paused
Running
Running
Run Code Online (Sandbox Code Playgroud)