- Goroutines
- Race Conditions
- Wait Groups
- Channels
- Unbuffered vs Buffered
- Select
- Set a timeout
The scheduler runs a goroutine in the most opportune time
type food struct {
seeds int
}
func main() {
food := food{seeds: 5}
go eat(&food)
time.Sleep(100 * time.Millisecond)
}
func eat(f *food) {
f.seeds--
fmt.Println(f.seeds)
}
When two or more goroutines attempt to read and write to the same resource at the same time.
type food struct {
seeds int
sync.Mutex
}
func main() {
food := food{seeds: 5}
go eat(&food)
go eat(&food)
time.Sleep(100 * time.Millisecond)
}
func eat(f *food) {
f.Lock()
{
f.seeds--
}
f.Unlock()
fmt.Println(f.seeds)
}
Note: Goroutines need to be coordinated and synchronized.
Waits for a collection of goroutines to finish.
func main() {
food := food{seeds: 5}
var wg sync.WaitGroup
wg.Add(2)
go eat(&food, &wg)
go eat(&food, &wg)
wg.Wait()
}
func eat(f *food, wg *sync.WaitGroup) {
f.Lock()
{
f.seeds--
}
f.Unlock()
wg.Done()
fmt.Println(f.seeds)
}
Channels figure out when a goroutine is done
type food struct {
seeds chan int
sync.Mutex
}
func eat(f *food, wg *sync.WaitGroup) {
defer wg.Done()
f.Lock()
{
seeds := <-f.seeds
seeds--
fmt.Println(seeds)
}
f.Unlock()
}
func main() {
food := food{seeds: make(chan int)}
var wg sync.WaitGroup
wg.Add(1)
go eat(&food, &wg)
food.seeds <- 2
wg.Wait()
}
Synchronous channel to make sure a channel finishes.
Note: Receivers always block until there is data to receive
Don't force goroutines to be ready at the same instant to perform sends and receives
func main() {
food := food{seeds: make(chan int, 1)}
var wg sync.WaitGroup
wg.Add(1)
food.seeds <- 2
go eat(&food, &wg)
wg.Wait()
}
A statement like switch for goroutines. It picks the first channel that is ready and receives from it
func eat(f *food, wg *sync.WaitGroup) {
defer wg.Done()
for {
select {
case <-f.seed:
fmt.Println("eating a seed")
return
case <-f.berry:
fmt.Println("eating a berry")
}
}
}
func main() {
food := food{
seed: make(chan bool),
berry: make(chan bool),
}
var wg sync.WaitGroup
wg.Add(1)
go eat(&food, &wg)
food.berry <- true
food.seed <- true
wg.Wait()
}
Setting a time limit!
func eat(f *food, wg *sync.WaitGroup) {
defer wg.Done()
for {
select {
case <-f.seed:
fmt.Println("eating a seed")
case <-f.berry:
fmt.Println("eating a berry")
case <-time.After(1000 * time.Millisecond):
fmt.Println("gopher ran home!")
return
}
}
}