如何暂停并恢复goroutine?

如何暂停并恢复goroutine?,go,concurrency,channel,goroutine,Go,Concurrency,Channel,Goroutine,我试着停下来,继续发牢骚。我知道我可以sleep跑步,但我要寻找的是一个“暂停/恢复”按钮,而不是计时器 这是我的尝试。我正在使用通道的阻塞功能暂停,并选择根据通道值切换要执行的内容。但是,在我的例子中,输出总是运行 func main() { ctx := wctx{} go func(ctx wctx) { for { time.Sleep(1 * time.Second) select {

我试着停下来,继续发牢骚。我知道我可以
sleep
跑步,但我要寻找的是一个“暂停/恢复”按钮,而不是计时器

这是我的尝试。我正在使用通道的阻塞功能暂停,并
选择
根据通道值切换要执行的内容。但是,在我的例子中,输出总是
运行

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{}
}
func main(){
ctx:=wctx{}
go func(ctx wctx){
为了{
时间。睡眠(1*时间。秒)
挑选{

case您需要初始化通道,记住从nil通道读取总是阻塞


使用
默认值选择
,案例从不阻塞

以下是您的程序的修改版本,修复了上述问题:

package main

import (
    "fmt"
    "time"
)

func main() {
    ctx := wctx{
        pause:  make(chan struct{}),
        resume: make(chan struct{}),
    }

    go func(ctx wctx) {
        for {
            select {
            case <-ctx.pause:
                fmt.Println("Paused")
            case <-ctx.resume:
                fmt.Println("Resumed")
            }

            fmt.Println("Running")
            time.Sleep(time.Second)
        }
    }(ctx)

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

type wctx struct {
    pause  chan struct{}
    resume chan struct{}
}

主程序包
进口(
“fmt”
“时间”
)
func main(){
ctx:=wctx{
暂停:make(chan struct{}),
简历:make(chan struct{}),
}
go func(ctx wctx){
为了{
挑选{

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

为此,您应该使用一个由互斥体同步的“state”变量

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
}
测试它:

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)
输出(在上尝试):


暂停和恢复goroutine只有一种方法,但此功能存在于运行时内。否则,您可以尝试双重锁定和双重解锁互斥锁。通常,您不想这样做。听起来像是XY问题。您能解释为什么我需要在此处按引用传递吗?我想我没有修改结构的任何值,所以我不需要到
Running
Running
Running
Paused
Paused
Paused
Running
Running