在这个例子中,我们将运行一个goroutine,每秒钟在终端上打印一个点。重要的是,我们将与它进行手动交互。我们将启动、暂停、恢复和终止它。虽然它的工作原理和预期的一样,但它可以被改进,可能的改进已经被添加到代码的顶部,但我们现在要忽略它。这只是一个最基本的骨架。
例子
package main
import (
"log"
"runtime"
"time"
)
/**
The initial state of a work can only be started.
If there is no work started yet then obviously there is nothing to be paused/resumed/terminated.
Valid state progressions:
start > pause
> terminate
pause > resume
> terminate
resume > pause
> terminate
Based on the progression rules above, the previous state should be recorded and checked against the
new state. If it is an invalid progression, it should be handled appropriately. e.g., nop with a warning
*/
type state string
const (
start state = "started"
pause state = "paused"
resume state = "resumed"
terminate state = "terminated"
)
func main() {
signaller := make(chan state)
// This will print 1 because main() function is a goroutine
log.Println(runtime.NumGoroutine())
go handler(signaller)
// This will print 2 because we started handler() goroutine above
log.Println(runtime.NumGoroutine())
signaller<- start
time.Sleep(time.Second*3)
// This will print 3 because handler() goroutine will start work() goroutine
log.Println(runtime.NumGoroutine())
signaller<- pause
time.Sleep(time.Second*5)
// This will print 2 because handler() goroutine will stop work() goroutine
log.Println(runtime.NumGoroutine())
signaller<- resume
time.Sleep(time.Second*3)
// This will print 3 because handler() goroutine will again start work() goroutine
log.Println(runtime.NumGoroutine())
signaller<- terminate
time.Sleep(time.Second*3)
// This will print 1 because handler() goroutine will stop work() goroutine and then itself
log.Println(runtime.NumGoroutine())
}
func handler(signaller chan state) {
done := make(chan struct{})
for {
signal := <-signaller
switch signal {
case start:
log.Println(signal)
go work(done)
case pause:
done<- struct{}{}
log.Println(signal)
case resume:
log.Println(signal)
go work(done)
case terminate:
done<- struct{}{}
log.Println(signal)
return
default:
log.Println("unknown signal")
return
}
}
}
func work(done <-chan struct{}) {
for {
select {
case <-done:
return
default:
time.Sleep(time.Second)
log.Println(".")
}
}
}
测试
$ go run -race main.go
2020/11/14 12:43:14 1
2020/11/14 12:43:14 2
2020/11/14 12:43:14 started
2020/11/14 12:43:15 .
2020/11/14 12:43:16 .
2020/11/14 12:43:17 3
2020/11/14 12:43:17 .
2020/11/14 12:43:17 paused
2020/11/14 12:43:22 2
2020/11/14 12:43:22 resumed
2020/11/14 12:43:23 .
2020/11/14 12:43:24 .
2020/11/14 12:43:25 3
2020/11/14 12:43:25 .
2020/11/14 12:43:25 terminated
2020/11/14 12:43:28 1