finished using cancel signal to terminate goroutine

This commit is contained in:
Jian Han 2018-01-16 20:00:20 +10:00
parent 08e01c5a9c
commit dc703eecec

View File

@ -1,6 +1,11 @@
package main package main
import "fmt" import (
"fmt"
"time"
"github.com/davecgh/go-spew/spew"
)
// The goroutine has a few paths to termination: // The goroutine has a few paths to termination:
// • When it has completed its work. // • When it has completed its work.
@ -15,7 +20,7 @@ goroutines in some sort of organized fashion.
**/ **/
func main() { func main() {
cancellationSignal()
} }
// Here we see that the main goroutine passes a nil channel into doWork. Therefore, the // Here we see that the main goroutine passes a nil channel into doWork. Therefore, the
@ -44,6 +49,46 @@ func resourceLeak() {
fmt.Println("Done.") fmt.Println("Done.")
} }
// The way to successfully mitigate this is to establish a signal between the parent gorou
// tine and its children that allows the parent to signal cancellation to its children. By
// convention, this signal is usually a read-only channel named done. The parent gorou
// tine passes this channel to the child goroutine and then closes the channel when it
// wants to cancel the child goroutine. Heres an example:
func cancellationSignal() { func cancellationSignal() {
// Here we pass the done channel to the doWork function. As a convention, this channel is the first parameter.
doWork := func(
done <-chan interface{},
strings <-chan string,
) <-chan interface{} {
terminated := make(chan interface{})
go func() {
defer fmt.Println("doWork exited.")
defer close(terminated)
for {
select {
case s := <-strings:
fmt.Println(s)
// On this line we see the ubiquitous for-select pattern in use. One of our case statements
// is checking whether our done channel has been signaled. If it has, we return from the goroutine.
case t := <-done:
spew.Dump(t)
return
}
}
}()
return terminated
}
done := make(chan interface{})
terminated := doWork(done, nil)
// Here we create another goroutine that will cancel the goroutine spawned in
// doWork if more than one second passes.
go func() {
// Cancel the operation after 1 second.
time.Sleep(1 * time.Second)
fmt.Println("Canceling doWork goroutine...")
close(done)
}()
// This is where we join the goroutine spawned from doWork with the main goroutine.
<-terminated
fmt.Println("Done.")
} }