مقدمة حول مكتبة Go ants
ants
هي مكتبة عالية الأداء لإدارة الموارد المتنوعة التي تنفذ جدولة وإدارة عدد كبير من goroutines، مما يسمح بتقييد وإعادة استخدام الموارد، وبالتالي تحقيق تنفيذ أكثر كفاءة للمهام أثناء تطوير البرامج المتزامنة.
الميزات
- جدولة تلقائية لعدد هائل من goroutines وإعادة استخدامها.
- تنظيف منتظم لل goroutines منتهية الصلاحية لتوفير الموارد بشكل أكبر.
- توفير عدد كبير من واجهات المستخدم القيمة: تقديم المهام، الحصول على عدد ال goroutines التي تعمل، ضبط حجم التجمع بشكل ديناميكي، إطلاق التجمع، وإعادة تشغيل التجمع.
- التعامل بأناقة مع حالات الطوارئ لمنع انهيار البرنامج.
- إعادة استخدام الموارد توفر توفيرا كبيرًا في استخدام الذاكرة. في سيناريو المهام المتزامنة على نطاق واسع، فإنها تتمتع بأداء أعلى من توازن ال goroutine الأصلي.
- آلية غير تقييدية
كيفية عمل ants
الرسم البياني للتدفق
الصور المتحركة
التثبيت
باستخدام الإصدار v1 من ants
:
go get -u github.com/panjf2000/ants
باستخدام الإصدار v2 من ants
(تمكين GO111MODULE=on):
go get -u github.com/panjf2000/ants/v2
الاستخدام
عند كتابة برنامج Go متزامن يطلق عدداً كبيراً من goroutines، فإنه سيستهلك بالضرورة كمية كبيرة من موارد النظام (الذاكرة، وحدة المعالجة المركزية). من خلال استخدام ants
، يمكنك إنشاء تجمع من goroutines لإعادة استخدامها، مما يوفر الموارد ويحسن الأداء:
package main
import (
"fmt"
"sync"
"sync/atomic"
"time"
"github.com/panjf2000/ants/v2"
)
var sum int32
func myFunc(i interface{}) {
n := i.(int32)
atomic.AddInt32(&sum, n)
fmt.Printf("تشغيل مع %d\n", n)
}
func demoFunc() {
time.Sleep(10 * time.Millisecond)
fmt.Println("مرحباً بالعالم!")
}
func main() {
defer ants.Release()
runTimes := 1000
// استخدام التجمع العام.
var wg sync.WaitGroup
syncCalculateSum := func() {
demoFunc()
wg.Done()
}
for i := 0; i < runTimes; i++ {
wg.Add(1)
_ = ants.Submit(syncCalculateSum)
}
wg.Wait()
fmt.Printf("تشغيل ال goroutines: %d\n", ants.Running())
fmt.Printf("إكمال جميع المهام.\n")
// استخدام التجمع مع وظيفة،
// قم بتعيين 10 كحد لسعة تجمع goroutine و 1 ثانية كمدة انتهاء الصلاحية.
p, _ := ants.NewPoolWithFunc(10, func(i interface{}) {
myFunc(i)
wg.Done()
})
defer p.Release()
// تقديم المهام واحدة تلو الأخرى.
for i := 0; i < runTimes; i++ {
wg.Add(1)
_ = p.Invoke(int32(i))
}
wg.Wait()
fmt.Printf("تشغيل ال goroutines: %d\n", p.Running())
fmt.Printf("إكمال جميع المهام، النتيجة هي %d\n", sum)
}
تكوين التجميع (Pool Configuration)
// Option تمثل الدالة الاختيارية.
type Option func(opts *Options)
// Options تحتوي على جميع الخيارات التي ستُطبَّق عند ت察مه مجموعة ذباب (ants pool).
type Options struct {
// ExpiryDuration هو المدة الزمنية لمنظف الغوروتين لتنظيف تلك العمال المنتهية الصلاحية،
// يقوم المنظف بفحص جميع العمال كل `ExpiryDuration` وتنظيف تلك العمال التي لم تُستخدم لأكثر من `ExpiryDuration`.
ExpiryDuration time.Duration
// PreAlloc يشير ما إذا كان يجب عمل تخصيص مسبق للذاكرة عند تهئية المجموعة (Pool).
PreAlloc bool
// Max عدد الغوروتين الذي يعتادر على الغروب لدى pool.Submit.
// 0 (القيمة الافتراضية) يعني عدم وجود حد معين.
MaxBlockingTasks int
// عندما يكون Nonblocking صحيحًا، فإن Pool.Submit لن يتم له العقد أبدًا.
// سيتم إرجاع ErrPoolOverload عندما لا يمكن تنفيذ Pool.Submit مرة واحدة.
// عندما يكون Nonblocking صحيحًا، فإن MaxBlockingTasks غير فعال.
Nonblocking bool
// PanicHandler يُستخدم لمعالجة الانهيارات من كل غوروتين العامل.
// إذا كانت قيمته nil، ستُلقى الانهيارات خارجياً من غوروتين العامل مرة أخرى.
PanicHandler func(interface{})
// Logger هو المسجل المخصص لتسجيل المعلومات، إذا لم يتم تعيينه،
// سيتم استخدام المسجل الافتراضي من حزمة log.
Logger Logger
}
// WithOptions تقبل تكوين الخيارات بأكمله.
func WithOptions(options Options) Option {
return func(opts *Options) {
*opts = options
}
}
// WithExpiryDuration يقوم بإعداد فترة تنظيف غوروتين.
func WithExpiryDuration(expiryDuration time.Duration) Option {
return func(opts *Options) {
opts.ExpiryDuration = expiryDuration
}
}
// WithPreAlloc يشير إلى ما إذا كان يجب القيام بتخصيص مسبق للعمال.
func WithPreAlloc(preAlloc bool) Option {
return func(opts *Options) {
opts.PreAlloc = preAlloc
}
}
// WithMaxBlockingTasks يعيق عدد الحد الأقصى للغوروتين التي تعتادر عندما يصل إلى سعة المجموعة.
func WithMaxBlockingTasks(maxBlockingTasks int) Option {
return func(opts *Options) {
opts.MaxBlockingTasks = maxBlockingTasks
}
}
// WithNonblocking يشير إلى أن المجموعة ستعيد nil عندما لا يتوفر عمال.
func WithNonblocking(nonblocking bool) Option {
return func(opts *Options) {
opts.Nonblocking = nonblocking
}
}
// WithPanicHandler يقوم بتعيين معالج الانهيار.
func WithPanicHandler(panicHandler func(interface{})) Option {
return func(opts *Options) {
opts.PanicHandler = panicHandler
}
}
// WithLogger يقوم بإعداد مسجل مخصص.
func WithLogger(logger Logger) Option {
return func(opts *Options) {
opts.Logger = logger
}
}
مجموعة مخصصة (Custom Pool)
ants
توفر تهئية مجموعة المستخدم الخاصة بسعة مجموعة محددة؛ عن طريق استدعاء الطريقة NewPool
، يمكن تهئية مجموعة جديدة بالسعة المحددة على النحو التالي:
p, _ := ants.NewPool(10000)
تقديم المهمة (Task Submission)
يتم تقديم المهمات عن طريق استدعاء الطريقة ants.Submit(func())
:
ants.Submit(func(){})
ضبط سعة مجموعة الغوروتين ديناميكيًا (Dynamically Adjusting the Goroutine Pool Capacity)
يمكنك لضبط سعة مجموعة الغوروتين ديناميكيًا، يمكنك استخدام الطريقة Tune(int)
:
pool.Tune(1000) // ضبط سعته إلى 1000
pool.Tune(100000) // ضبط سعته إلى 100000
هذه الطريقة آمنة للتداول.
تخصيص تخصيصة الصف (Pre-allocate goroutine queue memory)
ants
تتيح لك تخصيص الذاكرة لجميع المجموعة، والتي يمكن أن تعزز أداء مجموعة الغوروتين في سيناريوهات معينة محددة. على سبيل المثال، في سيناريو يتطلب مجموعة سعة كبيرة جدًا وأداء كل مهمة في الغوروتين يستغرق وقتًا، فإن تخصيص الذاكرة مسبقًا لصف الغوروتين سيقلل من إعادة تخصيص الذاكرة غير الضرورية.
// ants ستخصص ذاكرة القدرة الكلية للمجموعة عند استدعاء هذه الدالة
p, _ := ants.NewPool(100000, ants.WithPreAlloc(true))
إطلاق المجموعة (Release the Pool)
pool.Release()
إعادة تشغيل المجموعة (Restart the Pool)
// من خلال استدعاء طريقة Reboot()، يمكنك إعادة تنشيط مجموعة تم تدميرها مسبقاً ووضعها مرة أخرى للاستخدام.
pool.Reboot()
حول ترتيب تنفيذ المهام
ants
لا تضمن ترتيب تنفيذ المهام، وترتيب التنفيذ لا يتطابق بالضرورة مع ترتيب الإرسال. هذا يرجع إلى أن ants
تقوم بمعالجة جميع المهام المُرسلة بشكل متزامن، وسيتم تعيين المهام للعاملين الذين يقومون بتشغيلها بشكل متزامن، مما يؤدي إلى تنفيذ المهام بترتيب متزامن وغير قطعي.