Skip to content

Commit

Permalink
goroutines cool
Browse files Browse the repository at this point in the history
  • Loading branch information
MKaczkow committed Mar 14, 2024
1 parent 6782808 commit 31145ab
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 3 deletions.
4 changes: 2 additions & 2 deletions learning_go/10_concurrency_in_Go/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ vet: fmt
.PHONY: vet

build: vet
go build goprocedures_no_deadlock.go
go build process_and_gather.go
.PHONY: build

run: vet
go run goprocedures_no_deadlock.go
go run process_and_gather.go
.PHONY: run
21 changes: 21 additions & 0 deletions learning_go/10_concurrency_in_Go/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ ch := make(chan int, 10) // buffered channel with capacity of 10
v, ok := <-ch
```
* use `sync.WaitGroup` to wait for all goroutines to finish and avoid panic
* `Add` method to add number of goroutines to wait for
* `Done` method to signal that goroutine has finished
* `Wait` method to block until all goroutines have finished
* when to use `buffered`, when to use `unbuffered` channels?
* `buffered` - useful when you know how many goroutines are created, want to reduce their number or reduce number of awaiting operations
```go
Expand Down Expand Up @@ -104,3 +107,21 @@ for {
* `API`s shouldn't be designed to use concurrency, because it's implementation detail, which should be hidden
* so, *don't expose anything concurrency-related in your API* seems to be a good rule of thumb
* avoid `goroutine leaks`
* it's possible to set time limit to op using `time.After` - this is called `timeout idiom`
```go
func timeLimit() (int, error) {
var result int
var err error
done := make(chan struct{})
go func() {
result, err = longRunningOp()
close(done)
}()
select {
case <-done:
return result, err
case <-time.After(2 * time.Second):
return 0, errors.New("timeout")
}
}
```
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package main

import "fmt"

func main() {
func ter_bckp_main() {
ch1 := make(chan int)
ch2 := make(chan int)
go func() {
Expand Down
53 changes: 53 additions & 0 deletions learning_go/10_concurrency_in_Go/process_and_gather.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package main

import (
"fmt"
"sync"
)

func processAndGather(in <-chan int, processor func(int) int, num int) []int {
// run monitoring goprocedure
out := make(chan int, num)
var wg sync.WaitGroup
wg.Add(num)
for i := 0; i < num; i++ {
// wait for all others
go func() {
defer wg.Done()
for v := range in {
out <- processor(v)
}
}()
}
// call close on out channel
go func() {
wg.Wait()
close(out)
}()
var result []int
for v := range out {
// for-range stops when out channel is closed
result = append(result, v)
}
// return result
return result
}

func main() {
// prepare correct arguments for processAndGather func and call it
input := make(chan int)
processor := func(num int) int {
return num * 2
}

go func() {
defer close(input)
for i := 0; i < 10; i++ {
input <- i
}
}()

result := processAndGather(input, processor, 10)

fmt.Println(result)
}

0 comments on commit 31145ab

Please sign in to comment.