Go-Antsların Tanıtımı

ants, büyük miktarda Go rutini planlamasını ve yönetimini uygulayan yüksek performanslı bir goroutine havuzu olup, kaynakların sınırlanması ve yeniden kullanılmasına izin vererek, eş zamanlı programlar geliştirilirken görevlerin daha verimli bir şekilde yürütülmesini sağlar.

Özellikler

  • Otomatik olarak büyük miktarda Go rutinlerini planlar ve yeniden kullanır.
  • Kaynakları daha fazla korumak için süresi dolan Go rutinlerini düzenli olarak temizler.
  • Görev gönderme, çalışan Go rutin sayısını alma, havuz büyüklüğünü dinamik olarak ayarlama, havuzu serbest bırakma ve havuzu yeniden başlatma gibi birçok faydalı arayüz sağlar.
  • Program çökmesini önlemek için panikleri zarif bir şekilde ele alır.
  • Kaynakların yeniden kullanılması, bellek kullanımını büyük ölçüde azaltır. Büyük ölçekli toplu eş zamanlı görevler senaryosunda, yerel Go rutin eş zamanlılığından daha yüksek performansa sahiptir.
  • Engelsiz bir mekanizma

ants Nasıl Çalışır

Akış Şeması

ants-akış-şeması

Canlandırılmış Görüntüler

Kurulum

ants v1 sürümünü kullanma:

go get -u github.com/panjf2000/ants

ants v2 sürümünü kullanma (GO111MODULE=on olarak etkinleştirilmiş):

go get -u github.com/panjf2000/ants/v2

Kullanım

Birçok Go rutinini başlatan eş zamanlı bir program yazarken, sistemin büyük miktarda kaynağı (bellek, CPU) tüketmesi kaçınılmazdır. ants kullanarak, Go rutinlerini yeniden kullanmak için bir goroutine havuzu örneği alarak kaynakları tasarruflu kullanabilir ve performansı artırabilirsiniz:

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 ile çalıştır\n", n)
}

func demoFunc() {
	time.Sleep(10 * time.Millisecond)
	fmt.Println("Merhaba Dünya!")
}

func main() {
	defer ants.Release()

	runTimes := 1000

	// Ortak havuzu kullanın.
	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("çalışan gorutinler: %d\n", ants.Running())
	fmt.Printf("tüm görevleri tamamla.\n")

	// Bir fonksiyonla havuzunu kullan,
	// 10'u goroutine havuzunun kapasitesi olarak ve 1 saniyeyi süresi dolan süre olarak ayarlayın.
	p, _ := ants.NewPoolWithFunc(10, func(i interface{}) {
		myFunc(i)
		wg.Done()
	})
	defer p.Release()
	// Görevleri birer birer gönderin.
	for i := 0; i < runTimes; i++ {
		wg.Add(1)
		_ = p.Invoke(int32(i))
	}
	wg.Wait()
	fmt.Printf("çalışan gorutinler: %d\n", p.Running())
	fmt.Printf("tüm görevler tamamlandı, sonuç: %d\n", sum)
}

Havuz Yapılandırması

// Option, isteğe bağlı işlevi temsil eder.
type Option func(opts *Options)

// Options, bir karıncalar havuzu örneğinin oluşturulurken uygulanacak tüm seçenekleri içerir.
type Options struct {
	// ExpiryDuration, atıl durumdaki işçileri temizlemek için çöpçatan gorutin aralığıdır,
	// çöpçatan, tüm işçileri her `ExpiryDuration` taramalıdır ve `ExpiryDuration` boyunca kullanılmamış
	// olan işçileri temizler.
	ExpiryDuration time.Duration

	// PreAlloc, Havuz'u başlatırken bellek önceden tahsis edilip edilmeyeceğini gösterir.
	PreAlloc bool

	// pool.Submit üzerinde engellenen gorutinlerin maksimum sayısı.
	// 0 (varsayılan değer), böyle bir sınırın olmadığı anlamına gelir.
	MaxBlockingTasks int

	// Nonblocking true olduğunda, Pool.Submit asla engellenmeyecek.
	// Pool.Submit hemen yapılamadığında ErrPoolOverload döndürülür.
	// Nonblocking true olduğunda, MaxBlockingTasks etkisiz hale gelir.
	Nonblocking bool

	// PanicHandler, her işçi gorutininden gelen panikleri işlemek için kullanılır.
	// nil ise, panikler işçi gorutinlerinden tekrar atılır.
	PanicHandler func(interface{})

	// Logger, bilgiyi kaydetmek için özelleştirilmiş kaydedici, ayarlanmazsa,
	// log paketinden varsayılan standart kaydedici kullanılır.
	Logger Logger
}

// WithOptions, tüm seçenekleri kabul eder.
func WithOptions(seçenekler Seçenekler) Seçenek {
	return func(opts *Options) {
		*opts = seçenekler
	}
}

// WithExpiryDuration, gorutinleri temizleme aralığını ayarlar.
func WithExpiryDuration(expiryDuration time.Duration) Seçenek {
	return func(opts *Options) {
		opts.ExpiryDuration = expiryDuration
	}
}

// WithPreAlloc, işçiler için bellek tahsis edilip edilmeyeceğini belirtir.
func WithPreAlloc(preAlloc bool) Seçenek {
	return func(opts *Options) {
		opts.PreAlloc = preAlloc
	}
}

// WithMaxBlockingTasks, havuz kapasitesine ulaşıldığında engellenen gorutinlerin maksimum sayısını ayarlar.
Seçenekli görevleri ayarlar.
func WithMaxBlockingTasks(maxBlockingTasks int) Option {
	return func(opts *Options) {
		opts.MaxBlockingTasks = maxBlockingTasks
	}
}

// WithNonblocking, kullanılamaz işçi olduğunda havuzun nil döndürmesini belirtir.
func WithNonblocking(nonblocking bool) Seçenek {
	return func(opts *Options) {
		opts.Nonblocking = nonblocking
	}
}

// WithPanicHandler, panik işleyiciyi ayarlar.
func WithPanicHandler(panicHandler func(interface{})) Seçenek {
	return func(opts *Options) {
		opts.PanicHandler = panicHandler
	}
}

// WithLogger, özelleştirilmiş bir kaydediciyi ayarlar.
func WithLogger(kaydedici Kaydedici) Seçenek {
	return func(opts *Options) {
		opts.Logger = kaydedici
	}
}

NewPool/NewPoolWithFunc çağrılırken çeşitli isteğe bağlı fonksiyonlar kullanılarak, ants.Optionsdaki her yapılandırma öğesinin değeri ayarlanabilir ve ardından bu değerler kullanılarak gorutin havuzunu özelleştirmek mümkündür.

Özel Havuz

ants, belirli bir havuz kapasitesine sahip kullanıcının kendi Havuz'unu anında oluşturmayı destekler; NewPool yöntemi çağrılarak, belirtilen kapasiteye sahip yeni bir Havuz aşağıdaki gibi oluşturulabilir:

p, _ := ants.NewPool(10000)

Görev Gönderimi

Görevler, ants.Submit(func()) yöntemi çağrılarak gönderilir:

ants.Submit(func(){})

Gorutin Havuz Kapasitesinin Dinamik Ayarlanması

Gorutin havuz kapasitesini dinamik olarak ayarlamak için, Tune(int) yöntemi kullanılabilir:

havuz.Tune(1000) // Kapasitesini 1000'e ayarla
havuz.Tune(100000) // Kapasitesini 100000'e ayarla

Bu yöntem, thread-safe'tir.

Gorutin Kuyruğu Belleğinin Önceden Tahsis Edilmesi

ants, genel havuz için belleği önceden tahsis etmenize olanak tanır, bu da belirli senaryolarda gorutin havuzunun performansını artırabilir. Örneğin, çok büyük bir kapasiteye ihtiyaç duyulan bir senaryoda ve her gorutin görevinin zaman alıcı olduğu bir durumda, gorutin kuyruğu için belleği önceden tahsis etmek gereksiz bellek yeniden tahsisini azaltacaktır.

// bu işlevi çağırdığınızda, karıncalar havuzu kapasitesinin tamamını önceden tahsis eder.
p, _ := ants.NewPool(100000, ants.WithPreAlloc(true))

Havuzu Serbest Bırakma

havuz.Release()

Havuzu Yeniden Başlatma

// Reboot() yöntemi çağrılarak, önceden yok edilen bir havuzu yeniden etkinleştirebilir ve tekrar kullanıma alabilirsiniz.
havuz.Reboot()

Görev yürütme sırası hakkında

ants, görev yürütme sırasını garanti etmez ve yürütme sırası gönderme sırasıyla mutlaka eşleşmez. Bu, ants'ın tüm görevleri eş zamanlı olarak işlemesinden kaynaklanmaktadır ve görevler eş zamanlı çalışan işçilere atanacak, bu da görevlerin eş zamanlı ve belirsiz bir sıra ile yürütülmesine neden olacaktır.