如何暂停和恢复 goroutine?
How to pause and resume goroutine?
我正在尝试暂停和恢复 groutine。我明白我可以 sleep
运行,但我要找的是像按钮 "pause/resume" 而不是计时器。
这是我的尝试。我正在使用通道的阻塞功能来暂停,并使用 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{}
}
您需要初始化通道,请记住从 nil 通道读取总是阻塞。
带有 default
案例的 select
永远不会阻塞。
这是您程序的修改版本,修复了上述问题:
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{}
}
A select
有多个就绪案例,伪随机选择一个。因此,如果 goroutine 是 "slow" 来检查这些通道,您可能会在 pause
和 resume
上发送一个值(假设它们被缓冲)以便从两个通道接收可以准备好,并且 resume
可以首先选择,在以后的迭代中 pause
当 goroutine 不应该再暂停时。
为此,您应该使用由互斥锁同步的 "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)
输出(在 Go Playground 上尝试):
Running
Running
Running
Paused
Paused
Paused
Running
Running
我正在尝试暂停和恢复 groutine。我明白我可以 sleep
运行,但我要找的是像按钮 "pause/resume" 而不是计时器。
这是我的尝试。我正在使用通道的阻塞功能来暂停,并使用 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{}
}
您需要初始化通道,请记住从 nil 通道读取总是阻塞。
带有 default
案例的 select
永远不会阻塞。
这是您程序的修改版本,修复了上述问题:
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{}
}
A select
有多个就绪案例,伪随机选择一个。因此,如果 goroutine 是 "slow" 来检查这些通道,您可能会在 pause
和 resume
上发送一个值(假设它们被缓冲)以便从两个通道接收可以准备好,并且 resume
可以首先选择,在以后的迭代中 pause
当 goroutine 不应该再暂停时。
为此,您应该使用由互斥锁同步的 "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)
输出(在 Go Playground 上尝试):
Running
Running
Running
Paused
Paused
Paused
Running
Running