Skip to content

Commit

Permalink
feat: add three patterns
Browse files Browse the repository at this point in the history
1. generator
2. fan-in
3. fan-out
  • Loading branch information
Yu-Jack committed Sep 5, 2022
1 parent 2f13069 commit 1d717a0
Show file tree
Hide file tree
Showing 13 changed files with 287 additions and 0 deletions.
8 changes: 8 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions .idea/go-concurrency-patterns.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions 01-generator/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Generator


通常可以拿來做 pipeline 使用,避免一次讀取太大量資料。 其他使用方式還有類似 graceful shutdown 的方法。

參考 [Generator Pattern](./main.go)

補充: 通常產生 channel 人最好要負責關閉 channel,原因有以下兩點

1. 無法向已 closed channel 寫入資料
2. 可以讀取已 closed channel 的資料
25 changes: 25 additions & 0 deletions 01-generator/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package main

import "fmt"

func generateData() <-chan int {
data := make(chan int, 1)

go func(data chan int) {
for i := 0; i < 10; i++ {
data <- i
}

close(data)
}(data)

return data
}

func main() {
data := generateData()

for d := range data {
fmt.Println(d)
}
}
6 changes: 6 additions & 0 deletions 02-fan-in/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Fan-in


通常可以拿來做一些限制流量或是想從多個 output 統一收集 input 使用。

參考 [Fan-In Pattern](./main.go)
55 changes: 55 additions & 0 deletions 02-fan-in/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package main

import (
"fmt"
"sync"
)

func generateData() <-chan int {
data := make(chan int, 1)

go func(data chan int) {
for i := 0; i < 10; i++ {
data <- i
}

close(data)
}(data)

return data
}

func fanIn(sources ...<-chan int) <-chan int {
target := make(chan int, 1)

go func() {
defer close(target)

wg := sync.WaitGroup{}

for _, source := range sources {
wg.Add(1)
go func(source <-chan int, target chan int) {
defer wg.Done()
for val := range source {
target <- val
}
}(source, target)
}

wg.Wait()

}()

return target
}

func main() {
data1 := generateData()
data2 := generateData()
target := fanIn(data1, data2)

for d := range target {
fmt.Println(d)
}
}
5 changes: 5 additions & 0 deletions 03-fan-out/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Fan-out

通常可以拿來當做 Message Queue 使用,從單一 input 散佈到各個地方去。

參考 [Fan-Out Pattern](./main.go)
53 changes: 53 additions & 0 deletions 03-fan-out/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package main

import (
"fmt"
"time"
)

func generateData() <-chan int {
data := make(chan int, 1)

go func(data chan int) {
for i := 0; i < 10; i++ {
data <- i
}

close(data)
}(data)

return data
}

func fanOut(data <-chan int) <-chan int {
target := make(chan int, 1)

go func(data <-chan int) {
defer close(target)
for val := range data {
target <- val
}
}(data)

return target
}

func main() {
data := generateData()
target1 := fanOut(data)
target2 := fanOut(data)

go func() {
for d := range target1 {
fmt.Printf("target1: %d\n", d)
}
}()

go func() {
for d := range target2 {
fmt.Printf("target2: %d\n", d)
}
}()

time.Sleep(1 * time.Second) // Easily use time.Sleep to wait them finished instead of sync.WaitGroup
}
5 changes: 5 additions & 0 deletions 04-fan-in-fan-out/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Fan-In and Fan-Out

把以上兩種做一個整合範例,雖然這範例看起來跟直接讀兩個 channel 很像,但實際上同個 target1 channel 是有可能拿到同樣的值的。

參考 [Fan-In and Fan-Out Pattern](./main.go)
83 changes: 83 additions & 0 deletions 04-fan-in-fan-out/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package main

import (
"fmt"
"sync"
"time"
)

func generateData() <-chan int {
data := make(chan int, 1)

go func(data chan int) {
for i := 0; i < 10; i++ {
data <- i
}

close(data)
}(data)

return data
}

func fanIn(sources ...<-chan int) <-chan int {
target := make(chan int, 1)

go func() {
defer close(target)

wg := sync.WaitGroup{}

for _, source := range sources {
wg.Add(1)
go func(source <-chan int, target chan int) {
defer wg.Done()
for val := range source {
target <- val
}
}(source, target)
}

wg.Wait()

}()

return target
}

func fanOut(data <-chan int) <-chan int {
target := make(chan int, 1)

go func(data <-chan int) {
defer close(target)
for val := range data {
target <- val
}
}(data)

return target
}

func main() {
data1 := generateData()
data2 := generateData()

target := fanIn(data1, data2)

target1 := fanOut(target)
target2 := fanOut(target)

go func() {
for d := range target1 {
fmt.Printf("target1: %d\n", d)
}
}()

go func() {
for d := range target2 {
fmt.Printf("target2: %d\n", d)
}
}()

time.Sleep(1 * time.Second) // Easily use time.Sleep to wait them finished instead of sync.WaitGroup
}
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# 介紹

此專案是 go concurrency patterns 的各式範例

# 大綱


| Number | Name |
|--------|-------------------------------------------|
| 1 | [Generator](./01-generator) |
| 2 | [Fan-In](./02-fan-in) |
| 3 | [Fan-Out](./03-fan-out) |
| 4 | [Fan-In and Fan-Out](./04-fan-in-fan-out) |

0 comments on commit 1d717a0

Please sign in to comment.