mirror of
https://github.com/crazybber/awesome-patterns.git
synced 2024-11-22 04:36:02 +03:00
added sync wait group with error handling
This commit is contained in:
parent
067d0b21f4
commit
412871154a
78
concurrency/waitgroup/error_handling.go
Normal file
78
concurrency/waitgroup/error_handling.go
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
import "sync"
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type Error struct {
|
||||||
|
message string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e Error) Error() string {
|
||||||
|
return e.message
|
||||||
|
}
|
||||||
|
|
||||||
|
func syncWaitWithErrorHandling() {
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
waitGroupLength := 8
|
||||||
|
errChannel := make(chan error, 1)
|
||||||
|
|
||||||
|
// Setup waitgroup to match the number of go routines we'll launch off
|
||||||
|
wg.Add(waitGroupLength)
|
||||||
|
finished := make(chan bool, 1) // this along with wg.Wait() are why the error handling works and doesn't deadlock
|
||||||
|
|
||||||
|
for i := 0; i < waitGroupLength; i++ {
|
||||||
|
|
||||||
|
go func(i int) {
|
||||||
|
fmt.Printf("Go routine %d executed\n", i+1)
|
||||||
|
|
||||||
|
// Sleep for the time needed for each other go routine to complete.
|
||||||
|
// This helps show that the program exists with the last go routine to fail.
|
||||||
|
// comment this line if you want to see it fail fast
|
||||||
|
time.Sleep(time.Duration(waitGroupLength - i))
|
||||||
|
|
||||||
|
time.Sleep(0) // only here so the time import is needed
|
||||||
|
|
||||||
|
// comment out the following 3 lines to see what happens without an error
|
||||||
|
// Note, the channel has a length of one so the last go routine to error
|
||||||
|
// will always be the last error.
|
||||||
|
|
||||||
|
if i%4 == 1 {
|
||||||
|
errChannel <- Error{fmt.Sprintf("Errored on routine %d", i+1)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark the wait group as Done so it does not hang
|
||||||
|
wg.Done()
|
||||||
|
}(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put the wait group in a go routine.
|
||||||
|
// By putting the wait group in the go routine we ensure either all pass
|
||||||
|
// and we close the "finished" channel or we wait forever for the wait group
|
||||||
|
// to finish.
|
||||||
|
//
|
||||||
|
// Waiting forever is okay because of the blocking select below.
|
||||||
|
go func() {
|
||||||
|
wg.Wait()
|
||||||
|
close(finished)
|
||||||
|
}()
|
||||||
|
|
||||||
|
// This select will block until one of the two channels returns a value.
|
||||||
|
// This means on the first failure in the go routines above the errChannel will release a
|
||||||
|
// value first. Because there is a "return" statement in the err check this function will
|
||||||
|
// exit when an error occurs.
|
||||||
|
//
|
||||||
|
// Due to the blocking on wg.Wait() the finished channel will not get a value unless all
|
||||||
|
// the go routines before were successful because not all the wg.Done() calls would have
|
||||||
|
// happened.
|
||||||
|
select {
|
||||||
|
case <-finished:
|
||||||
|
case err := <-errChannel:
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("error ", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Successfully executed all go routines")
|
||||||
|
}
|
@ -1,9 +1,15 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
func main() {
|
import "github.com/davecgh/go-spew/spew"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
t1 := make(DogsList, 0)
|
||||||
|
t2 := DogList{}
|
||||||
|
spew.Dump(t1, t2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DogsList []*Dog
|
||||||
|
|
||||||
type Dog struct {
|
type Dog struct {
|
||||||
Name string
|
Name string
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user