Pengantar Go ants

ants adalah kolam gorutin berkinerja tinggi yang mengimplementasikan penjadwalan dan pengelolaan sejumlah besar gorutin, memungkinkan pembatasan dan penggunaan ulang sumber daya, sehingga mencapai eksekusi tugas yang lebih efisien saat mengembangkan program konkuren.

Fitur

  • Secara otomatis menjadwalkan sejumlah besar gorutin dan menggunakan ulang.
  • Secara teratur membersihkan gorutin yang sudah kadaluwarsa untuk lebih menghemat sumber daya.
  • Menyediakan sejumlah antarmuka yang berguna: pengiriman tugas, mendapatkan jumlah gorutin yang sedang berjalan, menyesuaikan ukuran kolam secara dinamis, melepaskan kolam, dan me-restart kolam.
  • Menangani panic secara halus untuk mencegah kegagalan program.
  • Pemanfaatan ulang sumber daya sangat menghemat penggunaan memori. Dalam skenario tugas konkuren dalam skala besar, ini memiliki kinerja lebih tinggi dibanding konkurensi gorutin asli.
  • Mekanisme tanpa penahanan (non-blocking).

Bagaimana ants bekerja

Diagram Alir

ants-flowchart-cn

Gambar Animasi

Instalasi

Menggunakan versi ants v1:

go get -u github.com/panjf2000/ants

Menggunakan versi ants v2 (aktifkan GO111MODULE=on):

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

Penggunaan

Ketika menulis program konkuren Go yang meluncurkan sejumlah besar gorutin, akan tak terhindarkan mengonsumsi sejumlah besar sumber daya sistem (memori, CPU). Dengan menggunakan ants, Anda dapat menginstansiasi kolam gorutin untuk menggunakan ulang gorutin, menghemat sumber daya, dan meningkatkan kinerja:

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("berjalan dengan %d\n", n)
}

func demoFunc() {
	time.Sleep(10 * time.Millisecond)
	fmt.Println("Hello World!")
}

func main() {
	defer ants.Release()

	runTimes := 1000

	// Gunakan kolam biasa.
	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("gorutin yang sedang berjalan: %d\n", ants.Running())
	fmt.Printf("selesaikan semua tugas.\n")

	// Gunakan kolam dengan fungsi,
	// atur 10 sebagai kapasitas kolam gorutin dan 1 detik untuk durasi kadaluarsa.
	p, _ := ants.NewPoolWithFunc(10, func(i interface{}) {
		myFunc(i)
		wg.Done()
	})
	defer p.Release()
	// Kirim tugas satu per satu.
	for i := 0; i < runTimes; i++ {
		wg.Add(1)
		_ = p.Invoke(int32(i))
	}
	wg.Wait()
	fmt.Printf("gorutin yang sedang berjalan: %d\n", p.Running())
	fmt.Printf("selesaikan semua tugas, hasilnya %d\n", sum)
}

Konfigurasi Kolam Renang

// Option mewakili fungsi opsional.
type Option func(opts *Options)

// Options berisi semua opsi yang akan diterapkan saat menginstansiasi kolam semut.
type Options struct {
	// ExpiryDuration adalah periode untuk goroutine pemulung membersihkan pekerja yang kadaluwarsa,
	// pemulung memindai semua pekerja setiap `ExpiryDuration` dan membersihkan pekerja yang tidak digunakan lebih dari `ExpiryDuration`.
	ExpiryDuration time.Duration

	// PreAlloc menunjukkan apakah akan melakukan alokasi memori saat menginisialisasi Kolam.
	PreAlloc bool

	// Jumlah maksimum goroutine yang terblokir pada pool.Submit.
	// 0 (nilai default) berarti tidak ada batasan seperti itu.
	MaxBlockingTasks int

	// Ketika Nonblocking bernilai true, Pool.Submit tidak akan pernah diblokir.
	// ErrPoolOverload akan dikembalikan ketika Pool.Submit tidak dapat dilakukan sekaligus.
	// Saat Nonblocking bernilai true, MaxBlockingTasks tidak berlaku.
	Nonblocking bool

	// PanicHandler digunakan untuk menangani panic dari masing-masing goroutine pekerja.
	// jika nil, panic akan dilemparkan lagi dari goroutine pekerja.
	PanicHandler func(interface{})

	// Logger adalah logger yang disesuaikan untuk logging informasi, jika tidak diatur,
	// logger default dari paket log akan digunakan.
	Logger Logger
}

// WithOptions menerima konfigurasi opsi lengkap.
func WithOptions(options Options) Option {
	return func(opts *Options) {
		*opts = options
	}
}

// WithExpiryDuration menyetel waktu interval pembersihan goroutines.
func WithExpiryDuration(expiryDuration time.Duration) Option {
	return func(opts *Options) {
		opts.ExpiryDuration = expiryDuration
	}
}

// WithPreAlloc menunjukkan apakah harus mengalokasikan memori untuk pekerja.
func WithPreAlloc(preAlloc bool) Option {
	return func(opts *Options) {
		opts.PreAlloc = preAlloc
	}
}

// WithMaxBlockingTasks menyetel jumlah maksimum goroutines yang terblokir ketika mencapai kapasitas kolam.
func WithMaxBlockingTasks(maxBlockingTasks int) Option {
	return func(opts *Options) {
		opts.MaxBlockingTasks = maxBlockingTasks
	}
}

// WithNonblocking menunjukkan bahwa kolam akan mengembalikan nil ketika tidak ada pekerja yang tersedia.
func WithNonblocking(nonblocking bool) Option {
	return func(opts *Options) {
		opts.Nonblocking = nonblocking
	}
}

// WithPanicHandler menyetel penanganan panic.
func WithPanicHandler(panicHandler func(interface{})) Option {
	return func(opts *Options) {
		opts.PanicHandler = panicHandler
	}
}

// WithLogger menyetel logger yang disesuaikan.
func WithLogger(logger Logger) Option {
	return func(opts *Options) {
		opts.Logger = logger
	}
}

Dengan menggunakan berbagai fungsi opsional saat memanggil NewPool/NewPoolWithFunc, nilai dari setiap item konfigurasi dalam ants.Options dapat diatur, dan kemudian digunakan untuk menyesuaikan kolam goroutine.

Kolam Renang Kustom

ants mendukung menginstansiasi Kolam khusus pengguna dengan kapasitas kolam tertentu; dengan memanggil metode NewPool, sebuah kolam baru dengan kapasitas yang ditentukan dapat diinstansiasi sebagai berikut:

p, _ := ants.NewPool(10000)

Pengiriman Tugas

Tugas dikirim dengan memanggil metode ants.Submit(func()):

ants.Submit(func(){})

Penyesuaian Dinamis Kapasitas Kolam Goroutine

Untuk menyesuaikan secara dinamis kapasitas kolam goroutine, Anda dapat menggunakan metode Tune(int):

kolam.Tune(1000) // Menyetel kapasitasnya menjadi 1000
kolam.Tune(100000) // Menyetel kapasitasnya menjadi 100000

Metode ini aman digunakan oleh banyak thread.

Alokasi Awal Memori Antrian Goroutine

ants memungkinkan Anda untuk melakukan alokasi awal memori untuk seluruh kolam, yang dapat meningkatkan kinerja kolam goroutine dalam skenario tertentu. Misalnya, dalam skenario di mana diperlukan kolam dengan kapasitas yang sangat besar dan setiap tugas dalam goroutine membutuhkan waktu, alokasi awal memori untuk antrian goroutine akan mengurangi realokasi memori yang tidak perlu.

// ants akan melakukan alokasi awal untuk seluruh kapasitas kolam saat Anda memanggil fungsi ini
p, _ := ants.NewPool(100000, ants.WithPreAlloc(true))

Melepaskan Kolam

kolam.Release()

Restart Kolam

// Dengan memanggil metode Reboot(), Anda dapat mengaktifkan kembali kolam yang sebelumnya dihancurkan dan menggunakannya kembali.
kolam.Reboot()

Tentang urutan eksekusi tugas

ants tidak menjamin urutan eksekusi tugas, dan urutan eksekusi tidak selalu sesuai dengan urutan pengiriman. Hal ini disebabkan karena ants memproses semua tugas yang dikirimkan secara bersamaan, dan tugas-tugas akan ditugaskan kepada pekerja yang sedang berjalan secara bersamaan, sehingga menyebabkan eksekusi tugas dalam urutan bersamaan dan tidak dapat diprediksi.