1 گوروٹین کی تعارف
1.1 اتساق اور ہمزمانی کا بنیادی تصورات
اتساق اور ہمزمانی دو عام تصورات ہیں جو ملٹی-ٹھریڈ پروگرامنگ میں استعمال ہوتے ہیں۔ ان کا استعمال واقعات یا پروگرام کی اجراء کرنے کو وضاحت دینے کے لیے کیا جاتا ہے جو واقعتاً ایک ساتھ وقوع پذیر ہو سکتے ہیں۔
- اتساق کا مطلب ہے کہ متعدد کام ایک ہی وقت میں پروسیس ہوتے ہیں، لیکن صرف ایک کام ہر دیے گئے وقت میں قابل اجراء ہوتا ہے۔ کام باہمی طور پر ایک دوسرے کے ساتھ تیزی سے تبدیل ہوتے ہیں، جو صارف کو ایکجانب سے وقتنمائی اجراء کا جذبہ دیتے ہیں۔ اتساق ایک کور پراسیسر کے لیے مناسب ہوتا ہے۔
- ہمزمانی اس بات کا حوالہ دیتا ہے کہ متعدد کام واقعی طور پر ایک ساتھ ہم وقت میں اجراء ہو رہے ہیں، جو ملٹی-کور پرا سیسرز کی مدد سے ممکن ہوتا ہے۔
Go زبان کو اتساق کو فائن کرنے کیلئے بنایا گیا ہے جو کہ اس کے ابتدائی اہداف میں سے ایک ہے۔ یہ گوروٹینز اور چینل کے ذریعے کارکرنے میں ماہر اتساق پروگرامنگ کے ماڈلکو فراہم کرتا ہے۔ Go کا رن ٹائم گوروٹینز کو منظم کرتا ہے، اور ان گوروٹینز کو متعدد سسٹم ٹھریڈز پر شیڈول کرنے کے لیے قادر ہے تاکہ ہمزمان پروسیسنگ حاصل ہو سکے۔
1.2 Go زبان میں گوروٹینز
گوروٹینز، Go زبان میں اتساق کو حاصل کرنے کا بنیادی تصور ہیں۔ یہ Go کے رن ٹائم کی طرف سے منظم کیے گئے ہلکے وزن کے ٹھریڈز ہیں۔ صارف کے لحاظ سے، یہ ٹھریڈز کی طرح ہیں، مگر کم وسائل استعمال کرتے ہیں، اور زیادہ تیزی سے شروع ہوتے ہیں۔
گوروٹینزکی خصوصیات میں شامل ہیں:
- ہلکے وزن کی: گوروٹینز فلپہ سٹیک میموری کو کم کرتے ہیں مقابلہ عام ٹھریڈز سے، اور ان کی سٹیک سائز کو ضرورت کے مطابقات پر دینامیک طریقے سے بڑھانے یا کم کر سکتے ہیں۔
- کم اوور ہیڈ: گوروٹینز کے بنانے اور تباہ کرنے کا اوور ہیڈ عام ٹھریڈز کے مقابلے میں کم ہے۔
- آسان ارتباط کا ذریعہ: چینل گوروٹینز کے درمیان ایک آسان اور موثر ارتباط کا ذریعہ فراہم کرتے ہیں۔
- غیر بلاک کرنے والا ڈیزائن: کچھ عمل میں گوروٹینز دوسرے گوروٹینز کو بلاک نہیں کرتے ہیں۔ مثال کے طور پر، جب ایک گوروٹین ویٹ کر رہا ہوتا ہے to I/Oاآپریشن کے لئے، تو دوسرے گوروٹینز اجراء کرتے رہ سکتے ہیں۔
2 گوروٹینز کی تخلیق اور منظم کرنا
2.1 گوروٹین کیسے بنائیں
Go زبان میں، آپ go
کیلئے کلیدی لفظ کا استعمال کر کے آسانی سے گوروٹین بنا سکتے ہیں۔ جب آپ کسی فنکشن کو go
کیلئے کلیدی لفظ سے پہلے کرکے اس کو آغاز کرتے ہیں، تو یہ فنکشن ایک نئے گوروٹین میں غیر مسلسل طور پر اجراء ہوگا۔
ایک سادہ مثال دیکھیں:
package main
import (
"fmt"
"time"
)
// Define a function to print Hello
func sayHello() {
fmt.Println("Hello")
}
func main() {
// `go` کلیدی لفظ استعمال کرکے نیا گوروٹین شروع کریں
go sayHello()
// مین فنکشن ایک مدت کے لئے انتظار کرتا ہے تاکہ sayHello کو اجراء ہونے دیں
time.Sleep(1 * time.Second)
fmt.Println("Main function")
}
اوپر دیے گئے کوڈ میں، sayHello()
فنکشن نئے گوروٹین میں غیر مسلسل طور پر اجراء ہوگا۔ یعنی main()
فنکشن sayHello کو ختم ہونے سے پہلے تک نہیں رکے گا۔ لہذا، ہم time.Sleep
استعمال کرتے ہیں میں فنکشن کو رکھنے کیلئے، جو کہ صرف تشریحی مقاصد کے لیے ہے۔ حقیقی ترقی میں، ہم عام طور پر چینلز یا دوسرے ہم زمانت میں مختلف گوروٹینز کی اجراء کا تنظیم کرنے کے لئے چینلز یا دوسرے ہم زمانت طریقے استعمال کرتے ہیں۔
نوٹ: عملی اطلاقات میں،
time.Sleep()
کا استعمال گوروٹین کو مکمل ہونے کے لیے انتظار کرنے کے لیے نہیں ہونا چاہئے، چونکہ یہ ایک مستند ہم زمانت سنچرنائزیشن کا ذریعہ نہیں ہے۔
2.2 گوروٹین شیڈولنگ کا نظام
Go میں، گوروٹین کی شیڈولنگ کو Go رن ٹائم کا شیڈولر ہینڈل ہوتا ہے، جو کہ دستیاب منطقی پروسیسز پر اجراء وقت کا ترتیب دینے کے لیے ذمہ دار ہوتا ہے۔ Go شیڈولر مختصر ہوکر آرک نارک کا استعمال کرتا ہے (متعدد گوروٹینز جن کو متعدد او ایس ٹھریڈز پر نظر ثانی ہے) تاکہ ملٹی-کور پروسیسرز پر بہتر کارکردگی حاصل ہو سکے۔
جی او میکس پروکس اور منطقی پروسیسرز
GOMAXPROCS
ایک ماحولی متغیر ہے جو رن ٹائم شیڈولر کے لیئے دستیاب سب سے زیادہ سی پی یووں کی تعین کرتا ہے جس کی دیفالٹ قیمت میسین پر موجود سی پی یو کورز کی تعداد ہوتی ہے۔ گو رن ٹائم ایک ہر منطقی پروسیسرز کے لیئے ایک ایف اوس ٹھریڈ تفصیل کرتا ہے۔ GOMAXPROCS
کو تقریبا کرکے، ہم رن ٹائم کی عدد زیادہ سی پی یوز کیلئے فراہم کرسکتے ہیں۔
import "runtime"
func init() {
runtime.GOMAXPROCS(2)
}
اوپر دیے گئے کوڈ میں، ہم نے دو کور کی سب سے زیادہ قیمت کو مقرر کی ہے تاکہ، جب بھی کوئی مشین میں مزید کورز ہوں تب بھی صرف دو یا کم کورز استعمال ہوں۔
اسکیڈولر کا عمل
اسکیڈولر تین اہم موجودہ اشیاء کے ذریعے کام کرتا ہے: M (مشین)، P (پروسیسر)، اور G (گوروٹین)۔ M مشین یا ٹھریڈ کی تصورات کا باعث ہے، P اسکیڈولنگ کا سیاق و سباق کو ظاہر کرتا ہے، اور G ایک خصوصی گوروٹین کو ظاہر کرتا ہے۔
- M: مشین یا ٹھریڈ کو ظاہر کرتا ہے، جو آپریٹنگ سسٹم کرنل ٹھریڈ کے تصورات کی انتہائی سادہ صورت فراہم کرتا ہے۔
- P: گوروٹین کو اجراء کرنے کے لئے ضرورتی وسائل کو ظاہر کرتا ہے۔ ہر P کے اپنی مقامی گوروٹین قطار ہوتی ہے۔
- G: ایک گوروٹین کو ظاہر کرتا ہے، جو اسکیوشن اسٹیک، انسٹرکشن سیٹ، اور دیگر معلومات شامل ہوتی ہیں۔
گو سکیڈولر کے کام کرنے کے اصولات شامل ہیں:
- M کے پاس G اجراء کرنے کے لئے P ہونا ضروری ہے۔ اگر P نہ ہو، تو M کو ٹھریڈ کیش میں واپس بھیج دیا جائے گا۔
- جب G دوسرے G کے ذریعے روکا نہیں جاتا ہے (مثلاً، سسٹم کالز میں)، تو وہ ممکنہ حد تک وہی M پر چلتا ہے، جو G کی مقامی ڈیٹا کو زیادہ فائدے مند CPU کیش کے اشغالت کے لئے 'گرم' رکھنے میں مدد گار ہوتا ہے۔
- جب G روکا جاتا ہے، تو M اور P الگ ہو جائیں گے، اور P نیا M تلاش کرے گا یا نیا M کو دِلائے گا تاکہ دوسرے G کی خدمت کر سکے۔
go func() {
fmt.Println("Hello from Goroutine")
}()
مساوی کوڈ نئے گوروٹین شروع کرنے کا دکھاتا ہے، جو سکیڈولر کو اس نئے G کو اجراء کے لئے قطار میں شامل کرنے پر مجبور کرے گا۔
گوروٹین کی پریمپٹو سکیڈولنگ
ابتدائی مراحل میں، Go نے اپنی مشترکہ سکیڈولنگ استعمال کی تھی، یعنی کہ گوروٹینز کو اگر وہ بناوٹ کے لئے انتظاماتی طور پر نہ چھوڑیں تو وہ دوسرے گوروٹینز کو بھوکا رکھ سکتے ہیں۔ اب، Go اسکیڈولر پریمپٹو سکیڈولنگ کا عمل کرتا ہے، جو لمبے عرصے تک اجراء ہونے والے Gs کو روکنے کی اجازت دیتا ہے تاکہ دوسرے Gs کو اجراء کرنے کا موقع دے۔
2.3 گوروٹین کی حیاتی دورانیہ کا انتظام
آپ کے Go ایپلیکیشن کی قدرت ور استحکام کو یقینی بنانے کے لئے، گوروٹین کے حیاتی دورانیہ کے انتظام کو سمجھنا اور مناسب طریقے سے انتظام کرنا ضروری ہے۔ گوروٹینز چلانا آسان ہے، مگر بغیر مناسب انتظام کے، یہ معاملات جیسے کہ میموری لیک اور ریس کنڈیشنز کے لئے باعث بن سکتے ہیں۔
گوروٹینز کو محفوظ طریقے سے شروع کرنا
گوروٹین شروع کرنے سے پہلے، یہ یقینی بنائیں کہ اس کا ورک لوڈ اور رن-ٹائم خصوصیات کو سمجھا گیا ہو۔ گوروٹین کو واضح ابتدا اور اختتام ہونا چاہئیے تاکہ "گوروٹین یتیم" بغیر اختتام کی حالت میں بنانے سے بچا جا سکے۔
func worker(done chan bool) {
fmt.Println("Working...")
time.Sleep(time.Second) // مصنے ظاہر کرنے کی طرح خرچ کرنا
fmt.Println("Done Working.")
done <- true
}
func main() {
// یہاں، Go میں چینل میکانزم کا استعمال ہوتا ہے۔ آپ بس چینل کو ایک بنیادی پیغام قطار سمجھ سکتے ہیں، اور قطار ڈیٹا کو پڑھنے اور لکھنے کے لئے " <-" اوپریٹر استعمال کر سکتے ہیں۔
done := make(chan bool, 1)
go worker(done)
// گوروٹین کے ختم ہونے کا انتظار کریں
<-done
}
اوپر کا کوڈ دکھاتا ہے کہ کس طرح done
چینل کا استعمال کرتے ہوئے گوروٹین کا انتظار کرنے کا ایک طریقہ ہوتا ہے۔
نوٹ: یہ مثال Go میں چینل میکانزم کا استعمال کرتی ہے، جو بعد کے بابوں میں تفصیل سے دیکھایا جائے گا۔
گوروٹینز کی منسوخی
عام طور پر، پورے پروگرام کے ختم ہونے سے تمام گوروٹینز بے روا ہو جائیں گے۔ تاہم، لمبے عرصے تک چلنے والے سروسز میں، ہمیں گوروٹینز کو فعال طور پر بند کرنے کی ضرورت ہو سکتی ہے۔
- چینلز کا استعمال کر کے رکاوٹی علامات بھیجنا: گوروٹینز چینلز کو پول کرکے رکاوٹی علامات کی جانچ پڑتال کر سکتے ہیں۔
stop := make(chan struct{})
go func() {
for {
select {
case <-stop:
fmt.Println("رکاوٹی علامت حاصل ہو گئی ہے۔ بند کر رہا ہوں...")
return
default:
// نارمل طور پر عمل کریں
}
}
}()
// رکاوٹی علامت بھیجیں
stop <- struct{}{}
- **
context
پیکیج کو حیاتی دورانیہ کا انتظام کرنے کے لئے استعمال کرنا:**
ctx, cancel := context.WithCancel(context.Background())
go func(ctx context.Context) {
for {
select {
case <-ctx.Done():
fmt.Println("رکاوٹی علامت حاصل ہو گئی ہے۔ بند کر رہا ہوں...")
return
default:
// نارمل طور پر عمل کریں
}
}
}(ctx)
// جب آپ گوروٹین روکنا چاہتے ہیں
cancel()
context
پیکیج کا استعمال گوروٹین کے حیاتی دورانیہ کو مزید موزوں طریقے سے کنٹرول کرنے کی اجازت دیتا ہے، ٹائم آؤٹ اور معطلی کی قابلیت فراہم کرتا ہے۔ بڑے ایپلیکیشنز یا مائیکروسروسز میں، context
گوروٹین کی حیاتی دورانیہ کو کنٹرول کرنے کا مشورہ دیا جاتا ہے۔