āļŠāļąāļĄāļ āļēāļĐāļ“āđŒāđ€āļ—āļ„āļ™āļīāļ„ Go: Goroutine, Channel āđāļĨāļ° Concurrency

āļ„āļģāļ–āļēāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒāđ€āļ—āļ„āļ™āļīāļ„ Go āđ€āļāļĩāđˆāļĒāļ§āļāļąāļš goroutine, channel āđāļĨāļ° concurrency pattern āļ•āđˆāļēāļ‡āđ† āļ•āļąāļ§āļ­āļĒāđˆāļēāļ‡āđ‚āļ„āđ‰āļ” āļ‚āđ‰āļ­āļœāļīāļ”āļžāļĨāļēāļ”āļ—āļĩāđˆāļžāļšāļšāđˆāļ­āļĒ āđāļĨāļ°āļ„āļģāļ•āļ­āļšāļĢāļ°āļ”āļąāļšāļœāļđāđ‰āđ€āļŠāļĩāđˆāļĒāļ§āļŠāļēāļāļŠāļģāļŦāļĢāļąāļšāđ€āļ•āļĢāļĩāļĒāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒāđ€āļ—āļ„āļ™āļīāļ„ Go āļ›āļĩ 2026

āđ€āļ•āļĢāļĩāļĒāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒāđ€āļ—āļ„āļ™āļīāļ„ Go āļ„āļĢāļ­āļšāļ„āļĨāļļāļĄ goroutine channel āđāļĨāļ° concurrency pattern

āļ„āļģāļ–āļēāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒ Go āđ€āļāļĩāđˆāļĒāļ§āļāļąāļš goroutine, channel āđāļĨāļ° concurrency āđ€āļ›āđ‡āļ™āļŦāļąāļ§āļ‚āđ‰āļ­āļ—āļĩāđˆāļ—āđ‰āļēāļ—āļēāļĒāļ—āļĩāđˆāļŠāļļāļ”āļŠāļģāļŦāļĢāļąāļšāļœāļđāđ‰āļŠāļĄāļąāļ„āļĢāļ­āļĒāđˆāļēāļ‡āļŠāļĄāđˆāļģāđ€āļŠāļĄāļ­ āļ„āļ§āļēāļĄāđ€āļ‚āđ‰āļēāđƒāļˆāļ­āļĒāđˆāļēāļ‡āļĨāļķāļāļ‹āļķāđ‰āļ‡āđƒāļ™āđāļ™āļ§āļ„āļīāļ”āđ€āļŦāļĨāđˆāļēāļ™āļĩāđ‰āļ„āļ·āļ­āļŠāļīāđˆāļ‡āļ—āļĩāđˆāđāļĒāļāļ§āļīāļĻāļ§āļāļĢ Go āļĢāļ°āļ”āļąāļšāļ­āļēāļ§āļļāđ‚āļŠāļ­āļ­āļāļˆāļēāļāļœāļđāđ‰āļ—āļĩāđˆāļĒāļąāļ‡āđ€āļĢāļĩāļĒāļ™āļĢāļđāđ‰āļ āļēāļĐāļēāļ­āļĒāļđāđˆ āļ„āļđāđˆāļĄāļ·āļ­āļ™āļĩāđ‰āļĢāļ§āļšāļĢāļ§āļĄāļ„āļģāļ–āļēāļĄāļ—āļĩāđˆāļœāļđāđ‰āļŠāļąāļĄāļ āļēāļĐāļ“āđŒāļĄāļąāļāļ–āļēāļĄāđƒāļ™āļ›āļĩ 2026 āļžāļĢāđ‰āļ­āļĄāļ•āļąāļ§āļ­āļĒāđˆāļēāļ‡āđ‚āļ„āđ‰āļ”āļĢāļ°āļ”āļąāļš production āđāļĨāļ°āđ€āļŦāļ•āļļāļœāļĨāđ€āļšāļ·āđ‰āļ­āļ‡āļŦāļĨāļąāļ‡āđāļ•āđˆāļĨāļ°āļ„āļģāļ•āļ­āļš

āļœāļđāđ‰āļŠāļąāļĄāļ āļēāļĐāļ“āđŒāļ—āļ”āļŠāļ­āļšāļ­āļ°āđ„āļĢāļˆāļĢāļīāļ‡āđ†

āļāļēāļĢāļŠāļąāļĄāļ āļēāļĐāļ“āđŒ concurrency āļ‚āļ­āļ‡ Go āđ€āļ™āđ‰āļ™āļŠāļēāļĄāļ”āđ‰āļēāļ™: āļāļēāļĢāļˆāļąāļ”āļāļēāļĢāļ§āļ‡āļˆāļĢāļŠāļĩāļ§āļīāļ• goroutine, āļ„āļ§āļēāļĄāļŦāļĄāļēāļĒāļ‚āļ­āļ‡ channel (buffered āļāļąāļš unbuffered, āļŠāļ™āļīāļ” directional) āđāļĨāļ°āļāļēāļĢāļ›āļĢāļ°āļāļ­āļš pattern (fan-out/fan-in, worker pool, context cancellation) āļāļēāļĢāļ—āđˆāļ­āļ‡āļˆāļģ syntax āđ€āļžāļĩāļĒāļ‡āļ­āļĒāđˆāļēāļ‡āđ€āļ”āļĩāļĒāļ§āđ„āļĄāđˆāđ€āļžāļĩāļĒāļ‡āļžāļ­ â€” āļœāļđāđ‰āļŠāļąāļĄāļ āļēāļĐāļ“āđŒāļ„āļēāļ”āļŦāļ§āļąāļ‡āđƒāļŦāđ‰āļœāļđāđ‰āļŠāļĄāļąāļ„āļĢāļŠāļēāļĄāļēāļĢāļ–āļ§āļīāđ€āļ„āļĢāļēāļ°āļŦāđŒ race condition āđāļĨāļ° deadlock āđ„āļ”āđ‰

āļžāļ·āđ‰āļ™āļāļēāļ™ Goroutine: āļ„āļģāļ–āļēāļĄāļ—āļĩāđˆāļ–āļđāļāļ–āļēāļĄāđ€āļŠāļĄāļ­

āļĢāļ­āļšāđāļĢāļāļ‚āļ­āļ‡āļāļēāļĢāļŠāļąāļĄāļ āļēāļĐāļ“āđŒāļĄāļąāļāļ—āļ”āļŠāļ­āļšāļ§āđˆāļēāļœāļđāđ‰āļŠāļĄāļąāļ„āļĢāđ€āļ‚āđ‰āļēāđƒāļˆ goroutine āļˆāļĢāļīāļ‡āđ† āļŦāļĢāļ·āļ­āđ„āļĄāđˆ — āđ„āļĄāđˆāđƒāļŠāđˆāđāļ„āđˆāļ§āļīāļ˜āļĩāļŠāļĢāđ‰āļēāļ‡āļĄāļąāļ™

āļ–: Goroutine āļ„āļ·āļ­āļ­āļ°āđ„āļĢ āđāļĨāļ°āđāļ•āļāļ•āđˆāļēāļ‡āļˆāļēāļ OS thread āļ­āļĒāđˆāļēāļ‡āđ„āļĢ?

Goroutine āļ„āļ·āļ­āļŸāļąāļ‡āļāđŒāļŠāļąāļ™ concurrent āļ—āļĩāđˆāļĄāļĩāļ™āđ‰āļģāļŦāļ™āļąāļāđ€āļšāļē āļˆāļąāļ”āļāļēāļĢāđ‚āļ”āļĒ Go runtime scheduler āđ„āļĄāđˆāđƒāļŠāđˆāļĢāļ°āļšāļšāļ›āļāļīāļšāļąāļ•āļīāļāļēāļĢ Go runtime āļ—āļģ multiplexing goroutine āļŦāļĨāļēāļĒāļžāļąāļ™āļ•āļąāļ§āļĨāļ‡āļšāļ™ OS thread āļˆāļģāļ™āļ§āļ™āļ™āđ‰āļ­āļĒāđ‚āļ”āļĒāđƒāļŠāđ‰āđ‚āļĄāđ€āļ”āļĨāļāļēāļĢāļˆāļąāļ”āļ•āļēāļĢāļēāļ‡ M:N (M goroutine āļ–āļđāļāđāļĄāļ›āļĨāļ‡āļšāļ™ N OS thread)

goroutine_basics.gogo
package main

import (
	"fmt"
	"runtime"
	"sync"
)

func main() {
	// Print the number of OS threads available
	fmt.Println("GOMAXPROCS:", runtime.GOMAXPROCS(0))

	var wg sync.WaitGroup

	for i := 0; i < 10000; i++ {
		wg.Add(1)
		go func(id int) {
			defer wg.Done()
			// Each goroutine starts with ~2-8KB stack
			// OS threads typically start with 1-8MB
			_ = id
		}(i)
	}

	wg.Wait()
	fmt.Println("All 10,000 goroutines completed")
}

āļ„āļ§āļēāļĄāđāļ•āļāļ•āđˆāļēāļ‡āļŦāļĨāļąāļāļ—āļĩāđˆāļ„āļ§āļĢāļāļĨāđˆāļēāļ§āļ–āļķāļ‡āđƒāļ™āļāļēāļĢāļŠāļąāļĄāļ āļēāļĐāļ“āđŒ: goroutine āđ€āļĢāļīāđˆāļĄāļ•āđ‰āļ™āļ”āđ‰āļ§āļĒ stack 2-8KB āļ—āļĩāđˆāļ‚āļĒāļēāļĒāđ„āļ”āđ‰āđāļšāļšāđ„āļ”āļ™āļēāļĄāļīāļ āđ€āļ—āļĩāļĒāļšāļāļąāļš stack āļ„āļ‡āļ—āļĩāđˆ 1-8MB āļ‚āļ­āļ‡ OS thread āļāļēāļĢāļŠāļĨāļąāļšāļšāļĢāļīāļšāļ—āļĢāļ°āļĢāļ°āļŦāļ§āđˆāļēāļ‡ goroutine āļˆāļąāļ”āļāļēāļĢāđƒāļ™ user space āđ‚āļ”āļĒ Go scheduler āļŦāļĨāļĩāļāđ€āļĨāļĩāđˆāļĒāļ‡āļāļēāļĢāļŠāļĨāļąāļšāļšāļĢāļīāļšāļ—āļĢāļ°āļĢāļ°āļ”āļąāļš kernel āļ—āļĩāđˆāļĄāļĩāļ•āđ‰āļ™āļ—āļļāļ™āļŠāļđāļ‡āļ‚āļ­āļ‡ OS thread āļ—āļģāđƒāļŦāđ‰āļāļēāļĢāļŠāļĢāđ‰āļēāļ‡ goroutine 100,000 āļ•āļąāļ§āđ€āļ›āđ‡āļ™āđ€āļĢāļ·āđˆāļ­āļ‡āļ›āļāļ•āļī āđƒāļ™āļ‚āļ“āļ°āļ—āļĩāđˆ OS thread 100,000 āļ•āļąāļ§āļˆāļ°āđƒāļŠāđ‰āļ—āļĢāļąāļžāļĒāļēāļāļĢāļĢāļ°āļšāļšāļˆāļ™āļŦāļĄāļ”

āļ–: āđ€āļāļīāļ”āļ­āļ°āđ„āļĢāļ‚āļķāđ‰āļ™āđ€āļĄāļ·āđˆāļ­ goroutine āđ€āļāļīāļ” panic?

Panic āļ—āļĩāđˆāđ„āļĄāđˆāļ–āļđāļ recover āđƒāļ™ goroutine āđƒāļ”āļāđ‡āļ•āļēāļĄāļˆāļ°āļ—āļģāđƒāļŦāđ‰āđ‚āļ›āļĢāđāļāļĢāļĄāļ—āļąāđ‰āļ‡āļŦāļĄāļ”āļŦāļĒāļļāļ”āļ—āļģāļ‡āļēāļ™ āļ•āđˆāļēāļ‡āļˆāļēāļ exception āđƒāļ™ Java āļŦāļĢāļ·āļ­ Python āļ•āļĢāļ‡āļ—āļĩāđˆ panic āđāļžāļĢāđˆāļ‚āļķāđ‰āļ™āļ•āļēāļĄ call stack āļ‚āļ­āļ‡ goroutine āļ•āļąāļ§āđ€āļ­āļ‡ â€” āđ„āļĄāđˆāđƒāļŠāđˆ stack āļ‚āļ­āļ‡ goroutine āļ—āļĩāđˆāļŠāļĢāđ‰āļēāļ‡āļĄāļąāļ™āļ‚āļķāđ‰āļ™āļĄāļē āļ§āļīāļ˜āļĩāđ€āļ”āļĩāļĒāļ§āļ—āļĩāđˆāļˆāļ°āļ”āļąāļāļˆāļąāļšāđ„āļ”āđ‰āļ„āļ·āļ­āđƒāļŠāđ‰ recover() āļ āļēāļĒāđƒāļ™ deferred function āļ‚āļ­āļ‡ goroutine āđ€āļ”āļĩāļĒāļ§āļāļąāļ™

panic_recovery.gogo
package main

import "fmt"

func safeGo(fn func()) {
	go func() {
		defer func() {
			if r := recover(); r != nil {
				fmt.Println("recovered from panic:", r)
			}
		}()
		fn() // execute the actual work
	}()
}

func main() {
	safeGo(func() {
		panic("something went wrong")
	})

	// Give goroutine time to complete
	select {}
}

āļœāļđāđ‰āļŠāļąāļĄāļ āļēāļĐāļ“āđŒāļĄāļ­āļ‡āļŦāļēāļ„āļ§āļēāļĄāļ•āļĢāļ°āļŦāļ™āļąāļāļĢāļđāđ‰āļ§āđˆāļēāļšāļĢāļīāļāļēāļĢ Go āđƒāļ™āļŠāļ āļēāļžāđāļ§āļ”āļĨāđ‰āļ­āļĄ production āļˆāļ°āļŦāđˆāļ­āļŦāļļāđ‰āļĄāļāļēāļĢāđ€āļĢāļīāđˆāļĄāļ—āļģāļ‡āļēāļ™ goroutine āļ”āđ‰āļ§āļĒ recovery pattern āđ„āļĨāļšāļĢāļēāļĢāļĩāļ­āļĒāđˆāļēāļ‡ errgroup āļˆāļąāļ”āļāļēāļĢāđ€āļĢāļ·āđˆāļ­āļ‡āļ™āļĩāđ‰āđ„āļ”āđ‰āļ­āļĒāđˆāļēāļ‡āđ€āļĢāļĩāļĒāļšāļĢāđ‰āļ­āļĒāļāļ§āđˆāļē

āļ„āļ§āļēāļĄāļŦāļĄāļēāļĒāļ‚āļ­āļ‡ Channel: Buffered, Unbuffered āđāļĨāļ° Directional

āļ„āļģāļ–āļēāļĄāđ€āļāļĩāđˆāļĒāļ§āļāļąāļš channel āđ€āļ›āļīāļ”āđ€āļœāļĒāļ§āđˆāļēāļœāļđāđ‰āļŠāļĄāļąāļ„āļĢāđ€āļ‚āđ‰āļēāđƒāļˆāđ‚āļĄāđ€āļ”āļĨ concurrency āļ‚āļ­āļ‡ Go āļˆāļĢāļīāļ‡āđ† āļŦāļĢāļ·āļ­āđāļ„āđˆāļ—āđˆāļ­āļ‡āļˆāļģ pattern

āļ–: āļ„āļ§āļēāļĄāđāļ•āļāļ•āđˆāļēāļ‡āļĢāļ°āļŦāļ§āđˆāļēāļ‡ buffered āđāļĨāļ° unbuffered channel āļ„āļ·āļ­āļ­āļ°āđ„āļĢ?

Unbuffered channel (make(chan T)) āļ•āđ‰āļ­āļ‡āļāļēāļĢāđƒāļŦāđ‰āļ—āļąāđ‰āļ‡āļœāļđāđ‰āļŠāđˆāļ‡āđāļĨāļ°āļœāļđāđ‰āļĢāļąāļšāļžāļĢāđ‰āļ­āļĄāļžāļĢāđ‰āļ­āļĄāļāļąāļ™ â€” āļāļēāļĢāļŠāđˆāļ‡āļˆāļ°āļšāļĨāđ‡āļ­āļāļˆāļ™āļāļ§āđˆāļē goroutine āļ­āļ·āđˆāļ™āļˆāļ°āļĢāļąāļšāļ„āđˆāļē Buffered channel (make(chan T, n)) āļ­āļ™āļļāļāļēāļ•āđƒāļŦāđ‰āļŠāđˆāļ‡āđ„āļ”āđ‰āļŠāļđāļ‡āļŠāļļāļ” n āļ„āđˆāļēāđ‚āļ”āļĒāđ„āļĄāđˆāļšāļĨāđ‡āļ­āļ

channel_semantics.gogo
package main

import "fmt"

func main() {
	// Unbuffered: send blocks until receive is ready
	ch := make(chan string)
	go func() {
		ch <- "hello" // blocks here until main reads
	}()
	msg := <-ch
	fmt.Println(msg)

	// Buffered: send does not block until buffer is full
	buf := make(chan int, 3)
	buf <- 1 // does not block (buffer has space)
	buf <- 2 // does not block
	buf <- 3 // does not block
	// buf <- 4 would block — buffer is full

	fmt.Println(<-buf, <-buf, <-buf) // 1 2 3
}

āļ„āļģāļ–āļēāļĄāļ•āđˆāļ­āđ€āļ™āļ·āđˆāļ­āļ‡āļ—āļĩāđˆāļœāļđāđ‰āļŠāļąāļĄāļ āļēāļĐāļ“āđŒāļĄāļąāļāļ–āļēāļĄ: "āđ€āļĄāļ·āđˆāļ­āđ„āļŦāļĢāđˆāļ„āļ§āļĢāđ€āļĨāļ·āļ­āļāđƒāļŠāđ‰āđāļšāļšāđ„āļŦāļ™?" Unbuffered channel āļšāļąāļ‡āļ„āļąāļšāļāļēāļĢāļ‹āļīāļ‡āđ‚āļ„āļĢāđ„āļ™āļ‹āđŒ — āļĄāļĩāļ›āļĢāļ°āđ‚āļĒāļŠāļ™āđŒāđ€āļĄāļ·āđˆāļ­āļœāļđāđ‰āļŠāđˆāļ‡āļ•āđ‰āļ­āļ‡āļĢāļđāđ‰āļ§āđˆāļēāļœāļđāđ‰āļĢāļąāļšāļ›āļĢāļ°āļĄāļ§āļĨāļœāļĨāļ„āđˆāļēāđāļĨāđ‰āļ§ Buffered channel āđāļĒāļāđ€āļ§āļĨāļēāļ‚āļ­āļ‡āļœāļđāđ‰āļŠāđˆāļ‡āđāļĨāļ°āļœāļđāđ‰āļĢāļąāļšāļ­āļ­āļāļˆāļēāļāļāļąāļ™ â€” āļĄāļĩāļ›āļĢāļ°āđ‚āļĒāļŠāļ™āđŒāļŠāļģāļŦāļĢāļąāļš work queue āļŦāļĢāļ·āļ­ rate limiting āļ—āļĩāđˆāļĒāļ­āļĄāļĢāļąāļšāļ„āļ§āļēāļĄāļŦāļĒāđˆāļ­āļ™āđ„āļ”āđ‰āļĢāļ°āļ”āļąāļšāļŦāļ™āļķāđˆāļ‡

āļ–: āđ€āļāļīāļ”āļ­āļ°āđ„āļĢāļ‚āļķāđ‰āļ™āđ€āļĄāļ·āđˆāļ­āļ›āļīāļ” channel?

āļāļēāļĢāļ›āļīāļ” channel āļŠāđˆāļ‡āļŠāļąāļāļāļēāļ“āļ§āđˆāļēāđ„āļĄāđˆāļĄāļĩāļ„āđˆāļēāļˆāļ°āļ–āļđāļāļŠāđˆāļ‡āđ€āļ‚āđ‰āļēāļĄāļēāļ­āļĩāļ āļāļēāļĢ receive āļˆāļēāļ channel āļ—āļĩāđˆāļ›āļīāļ”āđāļĨāđ‰āļ§āļˆāļ°āļ„āļ·āļ™āļ„āđˆāļēāļ—āļąāļ™āļ—āļĩāļžāļĢāđ‰āļ­āļĄ zero value āļāļēāļĢāļŠāđˆāļ‡āļ„āđˆāļēāđ„āļ›āļĒāļąāļ‡ channel āļ—āļĩāđˆāļ›āļīāļ”āđāļĨāđ‰āļ§āļˆāļ°āļ—āļģāđƒāļŦāđ‰āđ€āļāļīāļ” panic āļĨāļđāļ› range āļšāļ™ channel āļˆāļ°āļ­āļ­āļāđ‚āļ”āļĒāļ­āļąāļ•āđ‚āļ™āļĄāļąāļ•āļīāđ€āļĄāļ·āđˆāļ­ channel āļ–āļđāļāļ›āļīāļ”

close_channel.gogo
package main

import "fmt"

func producer(ch chan<- int, count int) {
	for i := 0; i < count; i++ {
		ch <- i
	}
	close(ch) // signal: no more values
}

func main() {
	ch := make(chan int, 5)
	go producer(ch, 5)

	// range exits automatically when channel closes
	for val := range ch {
		fmt.Println("received:", val)
	}

	// Reading from closed channel returns zero value + false
	val, ok := <-ch
	fmt.Printf("after close: val=%d, ok=%v\n", val, ok)
}

āļˆāļļāļ”āļŠāļģāļ„āļąāļ: āļĄāļĩāđ€āļžāļĩāļĒāļ‡āļœāļđāđ‰āļŠāđˆāļ‡āđ€āļ—āđˆāļēāļ™āļąāđ‰āļ™āļ—āļĩāđˆāļ„āļ§āļĢāļ›āļīāļ” channel āđ„āļĄāđˆāđƒāļŠāđˆāļœāļđāđ‰āļĢāļąāļš āļāļēāļĢāļ›āļīāļ” channel āļ—āļĩāđˆ goroutine āļ­āļ·āđˆāļ™āļĒāļąāļ‡āđ€āļ‚āļĩāļĒāļ™āļ­āļĒāļđāđˆāļˆāļ°āļ—āļģāđƒāļŦāđ‰āđ€āļāļīāļ” panic

āļžāļĢāđ‰āļ­āļĄāļ—āļĩāđˆāļˆāļ°āļžāļīāļŠāļīāļ•āļāļēāļĢāļŠāļąāļĄāļ āļēāļĐāļ“āđŒ Go āđāļĨāđ‰āļ§āļŦāļĢāļ·āļ­āļĒāļąāļ‡āļ„āļĢāļąāļš?

āļāļķāļāļāļ™āļ”āđ‰āļ§āļĒāļ•āļąāļ§āļˆāļģāļĨāļ­āļ‡āđāļšāļšāđ‚āļ•āđ‰āļ•āļ­āļš, flashcards āđāļĨāļ°āđāļšāļšāļ—āļ”āļŠāļ­āļšāđ€āļ—āļ„āļ™āļīāļ„āļ„āļĢāļąāļš

āļ„āļģāļŠāļąāđˆāļ‡ Select: āļāļēāļĢ Multiplexing Channel

āļ–: select āļ—āļģāļ‡āļēāļ™āļ­āļĒāđˆāļēāļ‡āđ„āļĢ āđāļĨāļ°āđ€āļāļīāļ”āļ­āļ°āđ„āļĢāđ€āļĄāļ·āđˆāļ­āļŦāļĨāļēāļĒ case āļžāļĢāđ‰āļ­āļĄāļžāļĢāđ‰āļ­āļĄāļāļąāļ™?

āļ„āļģāļŠāļąāđˆāļ‡ select āļˆāļ°āļšāļĨāđ‡āļ­āļāļˆāļ™āļāļ§āđˆāļēāļŦāļ™āļķāđˆāļ‡āđƒāļ™āļāļēāļĢāļ”āļģāđ€āļ™āļīāļ™āļāļēāļĢ channel āļŠāļēāļĄāļēāļĢāļ–āļ”āļģāđ€āļ™āļīāļ™āļāļēāļĢāļ•āđˆāļ­āđ„āļ”āđ‰ āđ€āļĄāļ·āđˆāļ­āļŦāļĨāļēāļĒ case āļžāļĢāđ‰āļ­āļĄāļžāļĢāđ‰āļ­āļĄāļāļąāļ™ Go āļˆāļ°āļŠāļļāđˆāļĄāđ€āļĨāļ·āļ­āļ â€” āđ€āļžāļ·āđˆāļ­āļ›āđ‰āļ­āļ‡āļāļąāļ™āđ„āļĄāđˆāđƒāļŦāđ‰ case āđƒāļ”āļ–āļđāļāļĨāļ°āđ€āļĨāļĒ

select_multiplex.gogo
package main

import (
	"context"
	"fmt"
	"time"
)

func fetchFromAPI(ctx context.Context, url string) (string, error) {
	resultCh := make(chan string, 1)
	errCh := make(chan error, 1)

	go func() {
		// Simulate API call
		time.Sleep(200 * time.Millisecond)
		resultCh <- fmt.Sprintf("data from %s", url)
	}()

	select {
	case result := <-resultCh:
		return result, nil
	case err := <-errCh:
		return "", err
	case <-ctx.Done():
		// Context cancelled or timed out
		return "", ctx.Err()
	}
}

func main() {
	ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
	defer cancel()

	result, err := fetchFromAPI(ctx, "https://api.example.com/data")
	if err != nil {
		fmt.Println("error:", err)
		return
	}
	fmt.Println(result)
}

āļœāļđāđ‰āļŠāļąāļĄāļ āļēāļĐāļ“āđŒāļ—āļ”āļŠāļ­āļšāļŠāļ­āļ‡āļ­āļĒāđˆāļēāļ‡āļ”āđ‰āļ§āļĒ select: āļ„āļ§āļēāļĄāđ€āļ‚āđ‰āļēāđƒāļˆāļāļŽāļāļēāļĢāđ€āļĨāļ·āļ­āļāđāļšāļšāļŠāļļāđˆāļĄ āđāļĨāļ°āļ„āļ§āļēāļĄāļŠāļēāļĄāļēāļĢāļ–āđƒāļ™āļāļēāļĢāļĢāļ§āļĄ channel āļāļąāļš context.Context āļŠāļģāļŦāļĢāļąāļš pattern timeout āđāļĨāļ°āļāļēāļĢāļĒāļāđ€āļĨāļīāļ

Concurrency Pattern āļ—āļĩāđˆāļžāļšāļšāđˆāļ­āļĒāđƒāļ™āļāļēāļĢāļŠāļąāļĄāļ āļēāļĐāļ“āđŒ

āļāļēāļĢāļŠāļąāļĄāļ āļēāļĐāļ“āđŒ Go āļĢāļ°āļ”āļąāļš senior āđāļ—āļšāļ—āļļāļāļ„āļĢāļąāđ‰āļ‡āļĄāļąāļāļĄāļĩāļ„āļģāļ–āļēāļĄāđ€āļāļĩāđˆāļĒāļ§āļāļąāļšāļāļēāļĢāđ€āļ‚āļĩāļĒāļ™ pattern āļ•āđˆāļ­āđ„āļ›āļ™āļĩāđ‰āļˆāļēāļāļĻāļđāļ™āļĒāđŒ

Pattern Fan-Out/Fan-In

āļ–: āđ€āļ‚āļĩāļĒāļ™ pipeline fan-out/fan-in āļ—āļĩāđˆāļ›āļĢāļ°āļĄāļ§āļĨāļœāļĨāļĢāļēāļĒāļāļēāļĢāđāļšāļšāļ‚āļ™āļēāļ™āļāļąāļ™

Fan-out āļāļĢāļ°āļˆāļēāļĒāļ‡āļēāļ™āđ„āļ›āļĒāļąāļ‡āļŦāļĨāļēāļĒ goroutine Fan-in āļĢāļ§āļšāļĢāļ§āļĄāļœāļĨāļĨāļąāļžāļ˜āđŒāļˆāļēāļāļŦāļĨāļēāļĒ goroutine āđ€āļ‚āđ‰āļēāļŠāļđāđˆ channel āđ€āļ”āļĩāļĒāļ§

fanout_fanin.gogo
package main

import (
	"fmt"
	"sync"
)

// generator produces values on a channel
func generator(nums ...int) <-chan int {
	out := make(chan int)
	go func() {
		for _, n := range nums {
			out <- n
		}
		close(out)
	}()
	return out
}

// square reads from input, squares each value
func square(in <-chan int) <-chan int {
	out := make(chan int)
	go func() {
		for n := range in {
			out <- n * n
		}
		close(out)
	}()
	return out
}

// fanIn merges multiple channels into one
func fanIn(channels ...<-chan int) <-chan int {
	var wg sync.WaitGroup
	merged := make(chan int)

	for _, ch := range channels {
		wg.Add(1)
		go func(c <-chan int) {
			defer wg.Done()
			for val := range c {
				merged <- val
			}
		}(ch)
	}

	go func() {
		wg.Wait()
		close(merged) // close after all inputs are drained
	}()

	return merged
}

func main() {
	in := generator(2, 3, 4, 5, 6)

	// Fan out: two goroutines reading from same channel
	c1 := square(in)
	c2 := square(in)

	// Fan in: merge results
	for result := range fanIn(c1, c2) {
		fmt.Println(result)
	}
}

Insight āļŦāļĨāļąāļāļ—āļĩāđˆāļœāļđāđ‰āļŠāļąāļĄāļ āļēāļĐāļ“āđŒāļ•āđ‰āļ­āļ‡āļāļēāļĢ: channel generator āļ–āļđāļāđāļŠāļĢāđŒāļĢāļ°āļŦāļ§āđˆāļēāļ‡ c1 āđāļĨāļ° c2 āļ”āļąāļ‡āļ™āļąāđ‰āļ™āđāļ•āđˆāļĨāļ°āļ„āđˆāļēāļˆāļ°āļ–āļđāļāļ›āļĢāļ°āļĄāļ§āļĨāļœāļĨāđ‚āļ”āļĒ worker āđ€āļžāļĩāļĒāļ‡āļ•āļąāļ§āđ€āļ”āļĩāļĒāļ§ (āđ„āļĄāđˆāļ‹āđ‰āļģāļāļąāļ™) āļŸāļąāļ‡āļāđŒāļŠāļąāļ™ fanIn āđƒāļŠāđ‰ WaitGroup āđ€āļžāļ·āđˆāļ­āļ—āļĢāļēāļšāļ§āđˆāļē input channel āļ—āļąāđ‰āļ‡āļŦāļĄāļ”āļ–āļđāļāļ­āđˆāļēāļ™āļˆāļ™āļŦāļĄāļ”āļāđˆāļ­āļ™āļ›āļīāļ” channel āļĢāļ§āļĄ

Worker Pool āļ”āđ‰āļ§āļĒ errgroup

āļ–: āđ€āļ‚āļĩāļĒāļ™ bounded worker pool āļ—āļĩāđˆāļĄāļĩāļāļēāļĢāļˆāļąāļ”āļāļēāļĢ error āļ­āļĒāđˆāļēāļ‡āđ„āļĢ?

Package golang.org/x/sync/errgroup (āļŠāđˆāļ§āļ™āļŦāļ™āļķāđˆāļ‡āļ‚āļ­āļ‡ Go extended standard library) āđāļāđ‰āļ›āļąāļāļŦāļēāļ™āļĩāđ‰āđ„āļ”āđ‰āļ­āļĒāđˆāļēāļ‡āđ€āļĢāļĩāļĒāļšāļĢāđ‰āļ­āļĒ āđ‚āļ”āļĒāļˆāļąāļ”āļāļēāļĢāļ§āļ‡āļˆāļĢāļŠāļĩāļ§āļīāļ• goroutine āļĢāļ§āļšāļĢāļ§āļĄ error āđāļĢāļ āđāļĨāļ°āļ—āļģāļ‡āļēāļ™āļĢāđˆāļ§āļĄāļāļąāļš context āļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāļĒāļāđ€āļĨāļīāļ

worker_pool.gogo
package main

import (
	"context"
	"fmt"
	"golang.org/x/sync/errgroup"
)

func processItem(ctx context.Context, id int) error {
	// Check for cancellation before heavy work
	select {
	case <-ctx.Done():
		return ctx.Err()
	default:
	}

	if id == 7 {
		return fmt.Errorf("failed to process item %d", id)
	}
	fmt.Printf("processed item %d\n", id)
	return nil
}

func main() {
	g, ctx := errgroup.WithContext(context.Background())
	g.SetLimit(3) // maximum 3 concurrent goroutines

	for i := 0; i < 10; i++ {
		id := i
		g.Go(func() error {
			return processItem(ctx, id)
		})
	}

	// Wait blocks until all goroutines finish
	// Returns the first non-nil error
	if err := g.Wait(); err != nil {
		fmt.Println("pipeline error:", err)
	}
}

āļ•āļąāđ‰āļ‡āđāļ•āđˆ Go 1.24 (āđ€āļ§āļ­āļĢāđŒāļŠāļąāļ™ stable āļĨāđˆāļēāļŠāļļāļ” āļ“ āļ•āđ‰āļ™āļ›āļĩ 2026) pattern āļ™āļĩāđ‰āļĒāļąāļ‡āļ„āļ‡āđ€āļ›āđ‡āļ™āļ§āļīāļ˜āļĩāļ—āļĩāđˆāđāļ™āļ°āļ™āļģ āđ€āļĄāļ˜āļ­āļ” SetLimit āļ–āļđāļāđ€āļžāļīāđˆāļĄāđƒāļ™ Go 1.20 āđāļĨāļ°āļ—āļģāđƒāļŦāđ‰āđ„āļĄāđˆāļ•āđ‰āļ­āļ‡āđ€āļ‚āļĩāļĒāļ™āļāļēāļĢāļˆāļģāļāļąāļ” concurrency āđāļšāļš semaphore āļ”āđ‰āļ§āļĒāļ•āļąāļ§āđ€āļ­āļ‡āļ­āļĩāļāļ•āđˆāļ­āđ„āļ›

Race Condition āđāļĨāļ° sync Primitive

āļ–: āļ•āļĢāļ§āļˆāļˆāļąāļšāđāļĨāļ°āļ›āđ‰āļ­āļ‡āļāļąāļ™ race condition āđƒāļ™ Go āļ­āļĒāđˆāļēāļ‡āđ„āļĢ?

Go āļĄāļĩ race detector āđƒāļ™āļ•āļąāļ§āļ—āļĩāđˆāđ€āļ›āļīāļ”āđƒāļŠāđ‰āļ‡āļēāļ™āļ”āđ‰āļ§āļĒ flag -race āđ€āļ„āļĢāļ·āđˆāļ­āļ‡āļĄāļ·āļ­āļ™āļĩāđ‰āļ•āļĢāļ§āļˆāļˆāļąāļšāļāļēāļĢāđ€āļ‚āđ‰āļēāļ–āļķāļ‡ shared memory āđāļšāļš concurrent āļ—āļĩāđˆāđ„āļĄāđˆāļ‹āļīāļ‡āđ‚āļ„āļĢāđ„āļ™āļ‹āđŒāļāļąāļ™āđƒāļ™āļ‚āļ“āļ° runtime

race_condition.gogo
package main

import (
	"fmt"
	"sync"
	"sync/atomic"
)

// BAD: race condition — do not use in production
func unsafeCounter() int {
	counter := 0
	var wg sync.WaitGroup
	for i := 0; i < 1000; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			counter++ // DATA RACE: concurrent read/write
		}()
	}
	wg.Wait()
	return counter // result is non-deterministic
}

// GOOD: atomic operations for simple counters
func atomicCounter() int64 {
	var counter atomic.Int64
	var wg sync.WaitGroup
	for i := 0; i < 1000; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			counter.Add(1) // thread-safe atomic increment
		}()
	}
	wg.Wait()
	return counter.Load() // always 1000
}

// GOOD: mutex for complex shared state
type SafeMap struct {
	mu sync.RWMutex
	data map[string]int
}

func (m *SafeMap) Set(key string, val int) {
	m.mu.Lock()         // exclusive lock for writes
	defer m.mu.Unlock()
	m.data[key] = val
}

func (m *SafeMap) Get(key string) (int, bool) {
	m.mu.RLock()         // shared lock for reads
	defer m.mu.RUnlock()
	v, ok := m.data[key]
	return v, ok
}

func main() {
	fmt.Println("unsafe:", unsafeCounter())  // unpredictable
	fmt.Println("atomic:", atomicCounter())  // always 1000
}

āļ„āļģāļ•āļ­āļšāļŠāļąāļĄāļ āļēāļĐāļ“āđŒāļ„āļ§āļĢāļ„āļĢāļ­āļšāļ„āļĨāļļāļĄāļŠāļēāļĄāļāļĨāļĒāļļāļ—āļ˜āđŒāļāļēāļĢāļ‹āļīāļ‡āđ‚āļ„āļĢāđ„āļ™āļ‹āđŒ: sync.Mutex / sync.RWMutex āļŠāļģāļŦāļĢāļąāļš shared state āļ—āļĩāđˆāļ‹āļąāļšāļ‹āđ‰āļ­āļ™, sync/atomic āļŠāļģāļŦāļĢāļąāļš counter āđāļĨāļ° flag āļˆāļģāļ™āļ§āļ™āđ€āļĨāđ‡āļ, āđāļĨāļ° channel āļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāļŠāļ·āđˆāļ­āļŠāļēāļĢāļĢāļ°āļŦāļ§āđˆāļēāļ‡ goroutine ("share memory by communicating, don’t communicate by sharing memory") āļāļēāļĢāļĢāļąāļ™ go test -race ./... āļ„āļ§āļĢāđ€āļ›āđ‡āļ™āļŠāđˆāļ§āļ™āļŦāļ™āļķāđˆāļ‡āļ‚āļ­āļ‡āļ—āļļāļ CI pipeline

Context āđāļĨāļ° Pattern āļāļēāļĢāļĒāļāđ€āļĨāļīāļ

āļ–: āļ­āļ˜āļīāļšāļēāļĒāļ§āđˆāļē context.Context āļ„āļ§āļšāļ„āļļāļĄāļ§āļ‡āļˆāļĢāļŠāļĩāļ§āļīāļ• goroutine āļ­āļĒāđˆāļēāļ‡āđ„āļĢ

Package context āļĄāļĩāļāļĨāđ„āļāļŠāļģāļŦāļĢāļąāļšāļŠāđˆāļ‡āļ•āđˆāļ­āļŠāļąāļāļāļēāļ“āļāļēāļĢāļĒāļāđ€āļĨāļīāļ deadline āđāļĨāļ°āļ„āđˆāļēāļ•āđˆāļēāļ‡āđ† āđƒāļ™āļĢāļ°āļ”āļąāļš request āļ‚āđ‰āļēāļĄāļ‚āļ­āļšāđ€āļ‚āļ•āļ‚āļ­āļ‡ goroutine āļ—āļļāļ goroutine āļ—āļĩāđˆāļ—āļģāļ‡āļēāļ™āļĒāļēāļ§āļ™āļēāļ™āļ„āļ§āļĢāļĢāļąāļš context.Context āđ€āļ›āđ‡āļ™āļžāļēāļĢāļēāļĄāļīāđ€āļ•āļ­āļĢāđŒāļ•āļąāļ§āđāļĢāļ

context_cancellation.gogo
package main

import (
	"context"
	"fmt"
	"time"
)

// worker simulates a long-running task
func worker(ctx context.Context, id int, results chan<- string) {
	select {
	case <-time.After(time.Duration(id*100) * time.Millisecond):
		results <- fmt.Sprintf("worker %d: done", id)
	case <-ctx.Done():
		results <- fmt.Sprintf("worker %d: cancelled (%v)", id, ctx.Err())
	}
}

func main() {
	// Parent context with 250ms deadline
	ctx, cancel := context.WithTimeout(context.Background(), 250*time.Millisecond)
	defer cancel()

	results := make(chan string, 5)

	// Launch 5 workers with increasing durations
	for i := 1; i <= 5; i++ {
		go worker(ctx, i, results)
	}

	// Collect all results
	for i := 0; i < 5; i++ {
		fmt.Println(<-results)
	}
}

Worker 1 āđāļĨāļ° 2 āļ—āļģāļ‡āļēāļ™āđ€āļŠāļĢāđ‡āļˆāļ āļēāļĒāđƒāļ™ deadline 250ms Worker 3, 4 āđāļĨāļ° 5 āđ„āļ”āđ‰āļĢāļąāļšāļŠāļąāļāļāļēāļ“āļĒāļāđ€āļĨāļīāļāļœāđˆāļēāļ™ ctx.Done() Pattern āļ™āļĩāđ‰āđ€āļ›āđ‡āļ™āļžāļ·āđ‰āļ™āļāļēāļ™āļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāļŠāļĢāđ‰āļēāļ‡ HTTP server āđāļĨāļ° microservice āļ—āļĩāđˆāļĄāļĩāļ„āļ§āļēāļĄāļ—āļ™āļ—āļēāļ™āđƒāļ™ Go — āļ—āļļāļ request handler āļˆāļ°āļĢāļąāļš context āļ—āļĩāđˆāļŠāđˆāļ‡āļ•āđˆāļ­āļŠāļąāļāļāļēāļ“āļĒāļāđ€āļĨāļīāļāđ€āļĄāļ·āđˆāļ­ client āļ•āļąāļ”āļāļēāļĢāđ€āļŠāļ·āđˆāļ­āļĄāļ•āđˆāļ­

āļāļąāļšāļ”āļąāļāļ—āļĩāđˆāļžāļšāļšāđˆāļ­āļĒāđƒāļ™āļŠāļąāļĄāļ āļēāļĐāļ“āđŒ

āļŦāđ‰āļēāļĄāđ€āļāđ‡āļš context.Context āđ„āļ§āđ‰āđƒāļ™ field āļ‚āļ­āļ‡ struct āđ€āļ­āļāļŠāļēāļĢāļ­āđ‰āļēāļ‡āļ­āļīāļ‡āļ‚āļ­āļ‡ Go āļĢāļ°āļšāļļāļŠāļąāļ”āđ€āļˆāļ™āļ§āđˆāļē: "Do not store Contexts inside a struct type; instead, pass a Context explicitly to each function that needs it." āļœāļđāđ‰āļŠāļąāļĄāļ āļēāļĐāļ“āđŒāļ—āļ”āļŠāļ­āļšāđ€āļĢāļ·āđˆāļ­āļ‡āļ™āļĩāđ‰āđ€āļžāļ·āđˆāļ­āļ›āļĢāļ°āđ€āļĄāļīāļ™āļ§āđˆāļēāļœāļđāđ‰āļŠāļĄāļąāļ„āļĢāļ›āļāļīāļšāļąāļ•āļīāļ•āļēāļĄāđāļ™āļ§āļ—āļēāļ‡āļ‚āļ­āļ‡ Go āļŦāļĢāļ·āļ­āđ„āļĄāđˆ

āļāļēāļĢāļ•āļĢāļ§āļˆāļˆāļąāļš Deadlock: āļ„āļģāļ–āļēāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒāđāļšāļšāļŦāļĨāļ­āļāļĨāđˆāļ­

āļ–: āđ‚āļ„āđ‰āļ”āļ™āļĩāđ‰āļˆāļ°āđ€āļāļīāļ” deadlock āļŦāļĢāļ·āļ­āđ„āļĄāđˆ? āđ€āļžāļĢāļēāļ°āļ­āļ°āđ„āļĢ?

āļ„āļģāļ–āļēāļĄāđ€āļĢāļ·āđˆāļ­āļ‡ deadlock āđ€āļ›āđ‡āļ™āļ—āļĩāđˆāļ™āļīāļĒāļĄāđ€āļžāļĢāļēāļ°āļ—āļ”āļŠāļ­āļšāļ„āļ§āļēāļĄāļŠāļēāļĄāļēāļĢāļ–āđƒāļ™āļāļēāļĢāļ§āļīāđ€āļ„āļĢāļēāļ°āļŦāđŒāļāļēāļĢāļˆāļąāļ”āļ•āļēāļĢāļēāļ‡ goroutine āđāļĨāļ°āļāļēāļĢāļ”āļģāđ€āļ™āļīāļ™āļāļēāļĢ channel

deadlock_example.gogo
package main

func main() {
	ch := make(chan int)
	ch <- 42 // DEADLOCK: unbuffered send with no receiver
	// The main goroutine blocks here forever
	// Go runtime detects this: "fatal error: all goroutines are asleep"
}

āļ§āļīāļ˜āļĩāđāļāđ‰āđ„āļ‚āļ•āļĢāļ‡āđ„āļ›āļ•āļĢāļ‡āļĄāļē: āļ—āļģ channel āđ€āļ›āđ‡āļ™āđāļšāļš buffered (make(chan int, 1)) āļŦāļĢāļ·āļ­āļŠāļĢāđ‰āļēāļ‡ goroutine āđ€āļžāļ·āđˆāļ­āļĢāļąāļšāļāđˆāļ­āļ™āļŠāđˆāļ‡ Go runtime āļ•āļĢāļ§āļˆāļˆāļąāļš deadlock āđ€āļĄāļ·āđˆāļ­āļ—āļļāļ goroutine āļ–āļđāļāļšāļĨāđ‡āļ­āļ â€” āđāļ•āđˆāđ€āļ‰āļžāļēāļ°āđ€āļĄāļ·āđˆāļ­ āļ—āļļāļāļ•āļąāļ§ āļŦāļĒāļļāļ”āļ—āļģāļ‡āļēāļ™ āļŦāļēāļāļĄāļĩāđāļĄāđ‰āđāļ•āđˆ goroutine āđ€āļ”āļĩāļĒāļ§āļ—āļĩāđˆāļĒāļąāļ‡āļ—āļģāļ‡āļēāļ™āļ­āļĒāļđāđˆ (āđ€āļŠāđˆāļ™ HTTP server āļ—āļĩāđˆāļ—āļģāļ‡āļēāļ™āļ­āļĒāļđāđˆāđ€āļšāļ·āđ‰āļ­āļ‡āļŦāļĨāļąāļ‡) runtime āļˆāļ°āđ„āļĄāđˆāļ•āļĢāļ§āļˆāļˆāļąāļš deadlock āļšāļēāļ‡āļŠāđˆāļ§āļ™

Deadlock āļšāļēāļ‡āļŠāđˆāļ§āļ™āļĄāļ­āļ‡āđ„āļĄāđˆāđ€āļŦāđ‡āļ™

Go runtime āļ•āļĢāļ§āļˆāļˆāļąāļš deadlock āđ„āļ”āđ‰āđ€āļ‰āļžāļēāļ°āđ€āļĄāļ·āđˆāļ­āļ—āļļāļ goroutine āđƒāļ™āđ‚āļ›āļĢāđāļāļĢāļĄāļ–āļđāļāļšāļĨāđ‡āļ­āļ āđƒāļ™āđāļ­āļ›āļžāļĨāļīāđ€āļ„āļŠāļąāļ™āļˆāļĢāļīāļ‡āļ—āļĩāđˆāļĄāļĩ HTTP server āļŦāļĢāļ·āļ­ background worker goroutine āļ—āļĩāđˆāļĢāļąāđˆāļ§āđ„āļŦāļĨāđāļĨāļ°āđ€āļāļīāļ” deadlock āļˆāļ°āđ„āļĄāđˆāļāļĢāļ°āļ•āļļāđ‰āļ™āļ•āļąāļ§āļ•āļĢāļ§āļˆāļˆāļąāļšāļ‚āļ­āļ‡ runtime āđ€āļ„āļĢāļ·āđˆāļ­āļ‡āļĄāļ·āļ­āļ­āļĒāđˆāļēāļ‡ pprof āđāļĨāļ° goroutine dump (runtime.Stack) āļˆāļģāđ€āļ›āđ‡āļ™āļŠāļģāļŦāļĢāļąāļšāļ§āļīāđ€āļ„āļĢāļēāļ°āļŦāđŒāļ›āļąāļāļŦāļēāđ€āļŦāļĨāđˆāļēāļ™āļĩāđ‰āđƒāļ™āļŠāļ āļēāļžāđāļ§āļ”āļĨāđ‰āļ­āļĄ production

Pattern āļ‚āļąāđ‰āļ™āļŠāļđāļ‡: āļāļēāļĢāļ›āļĢāļ°āļĄāļ§āļĨāļœāļĨāđāļšāļš Concurrent āļžāļĢāđ‰āļ­āļĄ Rate Limiting

āļ–: āđ€āļ‚āļĩāļĒāļ™ rate-limited concurrent API call āļ­āļĒāđˆāļēāļ‡āđ„āļĢ?

āļ„āļģāļ–āļēāļĄāļ™āļĩāđ‰āļ—āļ”āļŠāļ­āļšāļ„āļ§āļēāļĄāļŠāļēāļĄāļēāļĢāļ–āđƒāļ™āļāļēāļĢāļĢāļ§āļĄ concurrency primitive āļŦāļĨāļēāļĒāļ•āļąāļ§āđ€āļ‚āđ‰āļēāđ€āļ›āđ‡āļ™āđ‚āļ‹āļĨāļđāļŠāļąāļ™āļ—āļĩāđˆāļŠāļĄāļšāļđāļĢāļ“āđŒ

rate_limited.gogo
package main

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

// RateLimiter controls concurrent and temporal access
type RateLimiter struct {
	semaphore chan struct{}   // limits concurrency
	ticker    *time.Ticker    // limits rate
}

func NewRateLimiter(maxConcurrent int, interval time.Duration) *RateLimiter {
	return &RateLimiter{
		semaphore: make(chan struct{}, maxConcurrent),
		ticker:    time.NewTicker(interval),
	}
}

func (rl *RateLimiter) Execute(ctx context.Context, fn func() error) error {
	// Wait for rate limit tick
	select {
	case <-rl.ticker.C:
	case <-ctx.Done():
		return ctx.Err()
	}

	// Acquire concurrency slot
	select {
	case rl.semaphore <- struct{}{}:
	case <-ctx.Done():
		return ctx.Err()
	}

	defer func() { <-rl.semaphore }() // release slot
	return fn()
}

func main() {
	rl := NewRateLimiter(3, 100*time.Millisecond)
	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
	defer cancel()

	var wg sync.WaitGroup
	for i := 0; i < 10; i++ {
		wg.Add(1)
		go func(id int) {
			defer wg.Done()
			err := rl.Execute(ctx, func() error {
				fmt.Printf("[%v] processing %d\n", time.Now().Format("04:05.000"), id)
				time.Sleep(150 * time.Millisecond) // simulate work
				return nil
			})
			if err != nil {
				fmt.Printf("item %d: %v\n", id, err)
			}
		}(i)
	}
	wg.Wait()
}

Pattern āļ™āļĩāđ‰āļĢāļ§āļĄ semaphore āļ—āļĩāđˆāđƒāļŠāđ‰ channel (āļˆāļģāļāļąāļ” concurrency) āļāļąāļš ticker (āļˆāļģāļāļąāļ”āļ­āļąāļ•āļĢāļē) Double select āļ—āļĩāđˆāļ•āļĢāļ§āļˆāļŠāļ­āļš context āļĢāļąāļšāļ›āļĢāļ°āļāļąāļ™āļāļēāļĢ shutdown āđāļšāļš graceful āļ„āļģāļ•āļ­āļšāļĢāļ°āļ”āļąāļš production āđ€āļŠāđˆāļ™āļ™āļĩāđ‰āļ„āļ·āļ­āļŠāļīāđˆāļ‡āļ—āļĩāđˆāđāļĒāļāļœāļđāđ‰āļŠāļĄāļąāļ„āļĢāļĢāļ°āļ”āļąāļš senior āļ­āļ­āļāļˆāļēāļāļ„āļ™āļ­āļ·āđˆāļ™

āđ€āļĢāļīāđˆāļĄāļāļķāļāļ‹āđ‰āļ­āļĄāđ€āļĨāļĒ!

āļ—āļ”āļŠāļ­āļšāļ„āļ§āļēāļĄāļĢāļđāđ‰āļ‚āļ­āļ‡āļ„āļļāļ“āļ”āđ‰āļ§āļĒāļ•āļąāļ§āļˆāļģāļĨāļ­āļ‡āļŠāļąāļĄāļ āļēāļĐāļ“āđŒāđāļĨāļ°āđāļšāļšāļ—āļ”āļŠāļ­āļšāđ€āļ—āļ„āļ™āļīāļ„āļ„āļĢāļąāļš

āļŠāļĢāļļāļ›

  • Goroutine āđ€āļ›āđ‡āļ™ thread āļĢāļ°āļ”āļąāļš user-space āļ—āļĩāđˆ Go runtime āļˆāļąāļ”āļāļēāļĢāļ”āđ‰āļ§āļĒāļāļēāļĢāļĨāļģāļ”āļąāļš M:N; āļ•āđ‰āļ­āļ‡ recover panic āđƒāļ™ goroutine āļ—āļĩāđˆāļ–āļđāļ spawn āđ€āļŠāļĄāļ­
  • Unbuffered channel āļ‹āļīāļ‡āđ‚āļ„āļĢāđ„āļ™āļ‹āđŒāļœāļđāđ‰āļŠāđˆāļ‡āđāļĨāļ°āļœāļđāđ‰āļĢāļąāļš; buffered channel āđāļĒāļāđ€āļ§āļĨāļē — āđ€āļĨāļ·āļ­āļāļ•āļēāļĄāļ§āđˆāļēāļœāļđāđ‰āļŠāđˆāļ‡āļ•āđ‰āļ­āļ‡āļāļēāļĢāļāļēāļĢāļĒāļ·āļ™āļĒāļąāļ™āļŦāļĢāļ·āļ­āđ„āļĄāđˆ
  • āļ„āļģāļŠāļąāđˆāļ‡ select āļ—āļģ multiplexing āļāļēāļĢāļ”āļģāđ€āļ™āļīāļ™āļāļēāļĢ channel āļ”āđ‰āļ§āļĒāļāļēāļĢāđ€āļĨāļ·āļ­āļāļŠāļļāđˆāļĄāđ€āļĄāļ·āđˆāļ­āļŦāļĨāļēāļĒ case āļžāļĢāđ‰āļ­āļĄ; āđƒāļŠāđ‰āļĢāđˆāļ§āļĄāļāļąāļš context.Context āļŠāļģāļŦāļĢāļąāļš timeout
  • Fan-out/fan-in āđāļĨāļ° worker pool (āļœāđˆāļēāļ™ errgroup.SetLimit) āđ€āļ›āđ‡āļ™āļŠāļ­āļ‡ concurrency pattern āļ—āļĩāđˆāļ–āļđāļāļ–āļēāļĄāļšāđˆāļ­āļĒāļ—āļĩāđˆāļŠāļļāļ”
  • āđƒāļŠāđ‰ sync.Mutex āļŠāļģāļŦāļĢāļąāļš shared state āļ‹āļąāļšāļ‹āđ‰āļ­āļ™, sync/atomic āļŠāļģāļŦāļĢāļąāļš counter āļ‡āđˆāļēāļĒāđ†, āđāļĨāļ° channel āļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāļŠāļ·āđˆāļ­āļŠāļēāļĢāļĢāļ°āļŦāļ§āđˆāļēāļ‡ goroutine
  • āļĢāļąāļ™ go test -race āđƒāļ™ CI āđ€āļŠāļĄāļ­āđ€āļžāļ·āđˆāļ­āļˆāļąāļš data race; deadlock āļšāļēāļ‡āļŠāđˆāļ§āļ™āļ•āđ‰āļ­āļ‡āđƒāļŠāđ‰ pprof āđƒāļ™āļāļēāļĢāļ§āļīāđ€āļ„āļĢāļēāļ°āļŦāđŒ
  • āļŦāđ‰āļēāļĄāđ€āļāđ‡āļš context.Context āđƒāļ™ struct — āļŠāđˆāļ‡āđ€āļ›āđ‡āļ™āļžāļēāļĢāļēāļĄāļīāđ€āļ•āļ­āļĢāđŒāļ•āļąāļ§āđāļĢāļāļ‚āļ­āļ‡āļŸāļąāļ‡āļāđŒāļŠāļąāļ™
  • Rate limiting āđƒāļ™ Go āļĢāļ§āļĄ semaphore channel āļāļąāļš ticker āļŦāđˆāļ­āļŦāļļāđ‰āļĄāđƒāļ™ select statement āļ—āļĩāđˆāļĢāļąāļšāļĢāļđāđ‰ context

āđ€āļĢāļīāđˆāļĄāļāļķāļāļ‹āđ‰āļ­āļĄāđ€āļĨāļĒ!

āļ—āļ”āļŠāļ­āļšāļ„āļ§āļēāļĄāļĢāļđāđ‰āļ‚āļ­āļ‡āļ„āļļāļ“āļ”āđ‰āļ§āļĒāļ•āļąāļ§āļˆāļģāļĨāļ­āļ‡āļŠāļąāļĄāļ āļēāļĐāļ“āđŒāđāļĨāļ°āđāļšāļšāļ—āļ”āļŠāļ­āļšāđ€āļ—āļ„āļ™āļīāļ„āļ„āļĢāļąāļš

Anthony Fillion-Maillet

āđ€āļ‚āļĩāļĒāļ™āđ‚āļ”āļĒ

Anthony Fillion-Maillet

āļ™āļąāļāļžāļąāļ’āļ™āļēāļŸāļđāļĨāļŠāđāļ•āļ āļœāļđāđ‰āļāđˆāļ­āļ•āļąāđ‰āļ‡ SharpSkill

āđ€āļ›āđ‡āļ™āļ™āļąāļāļžāļąāļ’āļ™āļēāļŸāļđāļĨāļŠāđāļ•āļāļĄāļēāļāļ§āđˆāļē 10 āļ›āļĩ āļ”āļđāđāļĨ SharpSkill āđāļĨāļ°āļĢāļąāļšāļœāļīāļ”āļŠāļ­āļšāļ—āļļāļāļŠāļīāđˆāļ‡āļ—āļĩāđˆāđ€āļœāļĒāđāļžāļĢāđˆāļ—āļĩāđˆāļ™āļĩāđˆ

āļ­āļąāļ›āđ€āļ”āļ•āđ€āļĄāļ·āđˆāļ­ 1 āđ€āļĄāļĐāļēāļĒāļ™ 2569

āđāļ—āđ‡āļ

#go
#golang
#interview
#goroutines
#channels
#concurrency

āđāļŠāļĢāđŒ

āļšāļ—āļ„āļ§āļēāļĄāļ—āļĩāđˆāđ€āļāļĩāđˆāļĒāļ§āļ‚āđ‰āļ­āļ‡

āļāļēāļĢāļ—āļģāļ‡āļēāļ™āļžāļĢāđ‰āļ­āļĄāļāļąāļ™āļ‚āļ­āļ‡ Go - Goroutines āđāļĨāļ° channels āđƒāļ™āļāļēāļĢāļ—āļģāļ‡āļēāļ™

āļāļēāļĢāļ—āļģāļ‡āļēāļ™āļžāļĢāđ‰āļ­āļĄāļāļąāļ™āđƒāļ™ Go: Goroutines āđāļĨāļ° Channels - āļ„āļđāđˆāļĄāļ·āļ­āļ‰āļšāļąāļšāļŠāļĄāļšāļđāļĢāļ“āđŒ

āđ€āļŠāļĩāđˆāļĒāļ§āļŠāļēāļāļāļēāļĢāļ—āļģāļ‡āļēāļ™āļžāļĢāđ‰āļ­āļĄāļāļąāļ™āđƒāļ™ Go āļ”āđ‰āļ§āļĒ goroutines āđāļĨāļ° channels āļĢāļđāļ›āđāļšāļšāļ‚āļąāđ‰āļ™āļŠāļđāļ‡ āļāļēāļĢāļ‹āļīāļ‡āđ‚āļ„āļĢāđ„āļ™āļ‹āđŒ āļ„āļģāļŠāļąāđˆāļ‡ select āđāļĨāļ°āđāļ™āļ§āļ—āļēāļ‡āļ›āļāļīāļšāļąāļ•āļīāļ—āļĩāđˆāļ”āļĩāļ—āļĩāđˆāļŠāļļāļ”āļžāļĢāđ‰āļ­āļĄāļ•āļąāļ§āļ­āļĒāđˆāļēāļ‡āđ‚āļ„āđ‰āļ”āđ‚āļ”āļĒāļĨāļ°āđ€āļ­āļĩāļĒāļ”

āļ„āļģāļ–āļēāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒ Go - āļ„āļđāđˆāļĄāļ·āļ­āđ€āļ•āļĢāļĩāļĒāļĄāļ•āļąāļ§āļ‰āļšāļąāļšāļŠāļĄāļšāļđāļĢāļ“āđŒ

25 āļ„āļģāļ–āļēāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒ Go āļĒāļ­āļ”āļ™āļīāļĒāļĄ: āļ„āļđāđˆāļĄāļ·āļ­āļ‰āļšāļąāļšāļŠāļĄāļšāļđāļĢāļ“āđŒāļŠāļģāļŦāļĢāļąāļšāļ™āļąāļāļžāļąāļ’āļ™āļē

āļžāļīāļŠāļīāļ•āļāļēāļĢāļŠāļąāļĄāļ āļēāļĐāļ“āđŒ Go āļ”āđ‰āļ§āļĒ 25 āļ„āļģāļ–āļēāļĄāļ—āļĩāđˆāļ–āļđāļāļ–āļēāļĄāļšāđˆāļ­āļĒ goroutine, channel, interface āđāļĨāļ°āļĢāļđāļ›āđāļšāļšāļāļēāļĢāļ—āļģāļ‡āļēāļ™āļžāļĢāđ‰āļ­āļĄāļāļąāļ™āļžāļĢāđ‰āļ­āļĄāļ•āļąāļ§āļ­āļĒāđˆāļēāļ‡āđ‚āļ„āđ‰āļ”

āļ„āļđāđˆāļĄāļ·āļ­ Go āļŠāļģāļŦāļĢāļąāļšāļ™āļąāļāļžāļąāļ’āļ™āļē Java āđāļĨāļ° Python

Go: āļžāļ·āđ‰āļ™āļāļēāļ™āļŠāļģāļŦāļĢāļąāļšāļ™āļąāļāļžāļąāļ’āļ™āļē Java/Python āđƒāļ™āļ›āļĩ 2026

āđ€āļĢāļĩāļĒāļ™āļĢāļđāđ‰ Go āļ­āļĒāđˆāļēāļ‡āļĢāļ§āļ”āđ€āļĢāđ‡āļ§āđ‚āļ”āļĒāđƒāļŠāđ‰āļ›āļĢāļ°āļŠāļšāļāļēāļĢāļ“āđŒāļˆāļēāļ Java āļŦāļĢāļ·āļ­ Python Goroutine, channel, interface āđāļĨāļ° pattern āļŠāļģāļ„āļąāļāļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāđ€āļ›āļĨāļĩāđˆāļĒāļ™āļœāđˆāļēāļ™āļ­āļĒāđˆāļēāļ‡āļĢāļēāļšāļĢāļ·āđˆāļ™