Bu örnekte, terminalde her saniye noktalar basan bir goroutine çalıştıracağız. Burada önemli olan şey, onunla manuel olarak etkileşimde bulunacağımızdır. Başlayacağız, duraklatacağız, devam ettireceğiz ve sonlandıracağız. Beklendiği gibi çalışmasına rağmen mevcut olan kod iyileştirilebilir ve olası iyileştirmeler üstteki koda eklenmiştir, ancak şimdilik onu görmezden geleceğiz. Buradaki sadece en basitinden bir çıplak iskelettir.


Örnek


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(".")
}
}
}

Test


$ 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