البرمجة غير المتزامنة في Go: دليل شامل للمطورين

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

البرمجة غير المتزامنة في Go: المفاهيم الأساسية والتطبيق العملي



تم تصميم Go (Golang) منذ البداية كلغة للعمل بكفاءة مع المهام المتزامنة. على عكس العديد من اللغات الأخرى، حيث يتم تحقيق عدم التزامن من خلال callbacks أو مكتبات معقدة، تقدم Go أدوات بسيطة وأنيقة: goroutines و channels وعامل select. في هذا الدليل، سنشرح كيفية عمل البرمجة غير المتزامنة في Go، ونعرض أمثلة عملية.



1. Goroutines: خيوط تنفيذ خفيفة الوزن



Goroutine هو خيط تنفيذ خفيف الوزن، يتم إدارته بواسطة runtime الخاص بـ Go. على عكس خيوط النظام، تتمتع goroutines بتكاليف إضافية ضئيلة. يمكنك تشغيل آلاف من goroutines دون تأثير كبير على الأداء.



لتشغيل goroutine، يتم استخدام الكلمة المفتاحية go قبل استدعاء الدالة:



package main

import ( "fmt" "time")

func printMessage(msg string) { for i := 0; i < 5; i++ { fmt.Println(msg) time.Sleep(100 * time.Millisecond) }}

func main() { // تشغيل goroutine go printMessage("مخرجات غير متزامنة") // الخيط الرئيسي يواصل العمل printMessage("مخرجات متزامنة") // نعطي وقتًا للـ goroutine لكي تنتهي time.Sleep(1 * time.Second)}


من المهم أن تتذكر: الدالة الرئيسية main هي أيضًا goroutine. إذا انتهت، سيتم تدمير جميع goroutines الأخرى. لذلك غالبًا ما يتم استخدام sync.WaitGroup أو channels للمزامنة.



2. Channels: نقل آمن للبيانات بين goroutines



Channels هي "أنابيب" محددة النوع، يمكن من خلالها لـ goroutines تبادل البيانات. المبدأ الأساسي: "لا تتواصل عبر الذاكرة المشتركة؛ بل شارك الذاكرة عبر التواصل".



إنشاء واستخدام channel:



package main

import "fmt"

func main() { // إنشاء channel غير مخزن مؤقتًا من النوع int ch := make(chan int) // تشغيل goroutine تقوم بإرسال البيانات go func() { for i := 0; i < 5; i++ { ch <- i * 2 } close(ch) // إغلاق channel بعد إرسال جميع البيانات }() // قراءة البيانات من channel for value := range ch { fmt.Println("تم الاستلام:", value) }}


Channels المخزنة مؤقتًا (Buffered channels) تسمح بإرسال البيانات دون استلام فوري:



ch := make(chan string, 3) // مخزن مؤقت لـ 3 عناصرch <- "A"ch <- "B"ch <- "C"// الآن يمكن القراءةfmt.Println(<-ch) // Afmt.Println(<-ch) // B


3. عامل select: العمل مع عدة channels



عامل select يسمح لـ goroutine بانتظار عدة عمليات على channels في وقت واحد. يتم حظره حتى تصبح إحدى حالاته جاهزة للتنفيذ.



مثال مع مهلة زمنية ومعالجة عدة مصادر بيانات:



package main

import ( "fmt" "time")

func worker(id int, ch chan string) { time.Sleep(time.Duration(id) * time.Second) ch <- fmt.Sprintf("نتيجة من worker %d", id)}

func main() { ch1 := make(chan string) ch2 := make(chan string) go worker(2, ch1) // سينتهي بعد 2 ثانية go worker(3, ch2) // سينتهي بعد 3 ثوانٍ select { case msg1 := <-ch1: fmt.Println("القناة الأولى:", msg1) case msg2 := <-ch2: fmt.Println("القناة الثانية:", msg2) case <-time.After(1 * time.Second): fmt.Println("مهلة زمنية! لم ينجح أي worker في الوقت المحدد") } // إغلاق channels لمنع تسرب الذاكرة close(ch1) close(ch2)}


عامل select مثالي لتنفيذ المهلات الزمنية، والعمليات غير المحظورة، ونمط "fan-in" (دمج عدة channels في قناة واحدة).



4. أنماط التزامن في Go



نظر

المدونات

توصيات الكتب