
بریم سراغ اولین پترن: Fan-out / Fan-in — یکی از پایهایترین و در عین حال قدرتمندترین الگوهای همزمانی در گولنگ.
وقتی یک goroutine داده تولید میکنه و چند goroutine همزمان اون دادهها رو پردازش میکنن (fan-out)،
و بعد نتایج همهشون به یک کانال نهایی جمع میشه (fan-in).
Fan-out یعنی: چند goroutine بهصورت موازی از یک منبع داده (channel) داده میخوانند.
Fan-in یعنی: نتایج چند goroutine در یک channel نهایی ادغام میشود.
+------------+ | Source | +------------+ | v +-----------------------------+ | Fan-out Workers | | +--------+ +--------+ +--------+ | |Worker1 | |Worker2 | |Worker3 | | +--------+ +--------+ +--------+ +-----------------------------+ \ | / \ | / \ | / v v v +------------+ | Collector | +------------+
فرض کن میخوای اعداد ۱ تا ۳۰ رو بررسی کنی که آیا عدد اول (prime) هستن یا نه.
برای اینکه کار سریعتر انجام بشه، از ۳ goroutine استفاده میکنیم که همزمان این کار رو انجام بدن
package main import ( "fmt" "sync" ) // تابعی برای بررسی عدد اول بودن func isPrime(n int) bool { if n < 2 { return false } for i := 2; i*i <= n; i++ { if n%i == 0 { return false } } return true } // تولید اعداد func generateNumbers(nums ...int) <-chan int { out := make(chan int) go func() { for _, n := range nums { out <- n } close(out) }() return out } // worker که عدد میگیره و اگر اول بود، در خروجی میفرسته func checkPrime(in <-chan int) <-chan int { out := make(chan int) go func() { for n := range in { if isPrime(n) { out <- n } } close(out) }() return out } // ادغام چند channel خروجی در یک channel func merge(cs ...<-chan int) <-chan int { var wg sync.WaitGroup out := make(chan int) output := func(c <-chan int) { for n := range c { out <- n } wg.Done() } wg.Add(len(cs)) for _, c := range cs { go output(c) } go func() { wg.Wait() close(out) }() return out } func main() { // Fan-out: چند goroutine روی یک ورودی مشترک کار میکنن in := generateNumbers(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20) c1 := checkPrime(in) c2 := checkPrime(in) c3 := checkPrime(in) // Fan-in: ادغام همهی خروجیها out := merge(c1, c2, c3) for n := range out { fmt.Println(n) } }
generateNumbers() → اعداد را تولید میکند و در channel میفرستد.
checkPrime() → چند بار اجرا میشود (۳ worker داریم). هر worker از channel in میخواند و اگر عدد اول بود، در خروجی خودش میفرستد.
merge() → تمام خروجیهای workerها را یکی میکند (fan-in).
در آخر، main تمام نتایج را از out میخواند.