۰
Concurrency یکی از قدرتمندترین ویژگیهای زبان Go است که به شما امکان میدهد برنامههایی بسیار کارآمد و مقیاسپذیر بنویسید. در این چیتشیت، اصول اولیهی concurrency در Go — مانند goroutineها، channelها، sync.WaitGroup، mutexها و موارد دیگر — به همراه مثالهای کاربردی کد پوشش داده شده است. چه تازهکار باشید و چه بخواهید یک مرجع سریع داشته باشید، این راهنما برای شماست!
Goroutineها رشتههای (thread) سبک وزنی هستند که توسط runtime زبان Go مدیریت میشوند. آنها امکان اجرای همزمان کارها را با کمترین سربار فراهم میکنند.
1package main 2 3import ( 4 "fmt" 5 "time" 6) 7 8func printMessage(msg string) { 9 fmt.Println(msg) 10} 11 12func main() { 13 // شروع یک goroutine جدید 14 go printMessage("Hello from a goroutine!") 15 // زمان دادن به goroutine برای اتمام کار 16 time.Sleep(100 * time.Millisecond) 17 fmt.Println("Main function finished.") 18}
نکات کلیدی:
go
استفاده کنید.WaitGroup
) منتظر آنها بمانید.Channelها یک راه امن برای ارتباط بین goroutineها فراهم میکنند که در آن شما میتوانید پیامهای تایپ دار را ارسال و دریافت کنید.
1package main 2import "fmt" 3 4func sum(a, b int, result chan int) { 5 result <- a + b // فرستادن حاصل جمع به channel 6} 7 8func main() { 9 result := make(chan int) 10 go sum(3, 4, result) 11 fmt.Println("Sum:", <-result) // دریافت از channel 12}
1package main 2import "fmt" 3 4func main() { 5 ch := make(chan string, 2) // ایجاد channel با بافر ظرفیت 2 6 ch <- "Hello" 7 ch <- "World" 8 // خواندن بدون بلاک شدن 9 fmt.Println(<-ch) 10 fmt.Println(<-ch) 11}
نکات کلیدی:
sync.WaitGroup
برای منتظر ماندن تا تمام goroutineهای مشخص شده اجرا و به اتمام برسند، استفاده میشود.
1package main 2 3import ( 4 "fmt" 5 "sync" 6 "time" 7) 8 9func worker(id int, wg *sync.WaitGroup) { 10 defer wg.Done() // علامت پایان این goroutine 11 time.Sleep(100 * time.Millisecond) 12 fmt.Printf("Worker %d done\n", id) 13} 14 15func main() { 16 var wg sync.WaitGroup 17 // اجرای 5 worker 18 for i := 1; i <= 5; i++ { 19 wg.Add(1) 20 go worker(i, &wg) 21 } 22 // منتظر ماندن تا تمام workerها پایان یابند 23 wg.Wait() 24 fmt.Println("All workers completed.") 25}
نکات کلیدی:
wg.Add(n)
را فراخوانی کنید.defer wg.Done()
اعلام اتمام کند.wg.Wait()
استفاده کنید.Mutexها کمک میکنند تا شرایط رقابتی (race condition) جلوگیری شود و مطمئن شویم که تنها یک goroutine در هر لحظه به منبع مشترک دسترسی دارد.
1package main 2 3import ( 4 "fmt" 5 "sync" 6) 7 8func main() { 9 var mu sync.Mutex 10 counter := 0 11 12 increment := func() { 13 mu.Lock() 14 counter++ 15 mu.Unlock() 16 } 17 18 var wg sync.WaitGroup 19 for i := 0; i < 1000; i++ { 20 wg.Add(1) 21 go func() { 22 defer wg.Done() 23 increment() 24 }() 25 } 26 wg.Wait() 27 fmt.Println("Counter:", counter) 28}
وقتی تعداد خوانندهها زیاد و نویسندهها کم است، از sync.RWMutex
استفاده کنید.
1package main 2 3import ( 4 "fmt" 5 "sync" 6) 7 8func main() { 9 var mu sync.RWMutex 10 data := make(map[string]int) 11 12 // نویسنده 13 go func() { 14 mu.Lock() 15 data["key"] = 42 16 mu.Unlock() 17 }() 18 19 // خواننده 20 mu.RLock() 21 value := data["key"] 22 mu.RUnlock() 23 fmt.Println("Value:", value) 24}
دستور select
به شما اجازه میدهد که همزمان منتظر چند عملیات بر روی channelها باشید؛ شبیه به switch اما برای channelها.
1package main 2 3import ( 4 "fmt" 5 "time" 6) 7 8func main() { 9 ch1 := make(chan string) 10 ch2 := make(chan string) 11 12 go func() { 13 time.Sleep(50 * time.Millisecond) 14 ch1 <- "from ch1" 15 }() 16 17 go func() { 18 time.Sleep(100 * time.Millisecond) 19 ch2 <- "from ch2" 20 }() 21 22 select { 23 case msg1 := <-ch1: 24 fmt.Println("Received:", msg1) 25 case msg2 := <-ch2: 26 fmt.Println("Received:", msg2) 27 case <-time.After(150 * time.Millisecond): 28 fmt.Println("Timeout") 29 } 30}
نکات کلیدی:
select
بلاک میشود تا یکی از caseها آماده اجرا شدن شود.default
برای non-blocking کردن select استفاده کنید.پکیج context
به شما امکان میدهد که deadline، سیگنالهای لغو و دیگر مقادیر مرتبط با درخواست را بین boundaryهای API رد و بدل کنید.
1package main 2 3import ( 4 "context" 5 "fmt" 6 "time" 7) 8 9func longRunningTask(ctx context.Context) { 10 select { 11 case <-time.After(2 * time.Second): 12 fmt.Println("Task completed") 13 case <-ctx.Done(): 14 fmt.Println("Task canceled:", ctx.Err()) 15 } 16} 17 18func main() { 19 ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) 20 defer cancel() 21 longRunningTask(ctx) 22}
نکات کلیدی:
context.WithTimeout
یا context.WithCancel
برای کنترل مدت عمر goroutine استفاده کنید.ctx
را به توابعی که پشتیبانی از لغو دارند، پاس دهید.go run -race
شرایط رقابتی را در زمان توسعه پیدا کنید.pprof
محلهای گلوگاه concurrency را بشناسید.این چیتشیت اصول concurrency در Go را با مثالهای عملی و شیوههای برتر پوشش میدهد تا در نوشتن کدهای همزمان بهینه و امن به شما کمک کند. اگر این مطلب برایتان مفید بود، آن را به اشتراک بگذارید، نظرات خود را بگویید یا نکات بیشتر خود را اضافه کنید. کدنویسی خوش!
با دنبال کردن این راهنما، بنیان محکمی برای پیادهسازی و درک concurrency در Go خواهید داشت. از ساخت برنامههای مقیاسپذیر و کارآمد خود لذت ببرید!
۰
کد با می متعهد است که بالاترین سطح کیفی آموزش را در اختیار شما بگذارد. هدف به اشتراک گذاشتن دانش فناوری اطلاعات و توسعه نرم افزار در بالاترین سطح ممکن برای درستیابی به جامعه ای توانمند و قدرتمند است. ما باور داریم هر کسی میتواند با استمرار در یادگیری برنامه نویسی چالش های خود و جهان پیرامون خود را بر طرف کند و به موفقیت های چشم گیر برسد. با ما در این مسیر همراه باشید. کد با می اجتماع حرفه ای برنامه نویسان ایرانی.