Tunny เป็นไลบรารี Golang สำหรับสร้างและการจัดการกับ goroutine pools ซึ่งช่วยให้คุณจำกัดงานจากจำนวน goroutines ด้วย APIs ที่เป็นการทำงานแบบเสถียร

เมื่องานของคุณมาจากจำนวนของแหล่งที่มีการทำงานแบบไม่สม่ำเสมอ แต่ความสามารถในการประมวลผลแบบพร้อมกันของคุณจำกัดอยู่ ก็จะมีการใช้ fixed goroutine pool ที่มีประโยชน์มาก ตัวอย่างเช่น เมื่อประมวลกิจกรรม HTTP request ที่ใช้ CPU-intensive คุณสามารถสร้าง pool ที่มีขนาดเท่ากับจำนวนของ CPU

การติดตั้ง

go get github.com/Jeffail/tunny

หรือหากใช้ dep:

dep ensure -add github.com/Jeffail/tunny

การใช้

สำหรับกรณีส่วนใหญ่ งานที่มีน้ำหนักมากของคุณสามารถแสดงได้ด้วย func() ที่ง่าย ในกรณีนี้คุณสามารถใช้ NewFunc ให้ดูการใช้ตัวอย่างของเราโดยใช้ HTTP requests ไปยังการนับ CPU:

package main

import (
	"io/ioutil"
	"net/http"
	"runtime"

	"github.com/Jeffail/tunny"
)

func main() {
	numCPUs := runtime.NumCPU()

	pool := tunny.NewFunc(numCPUs, func(payload interface{}) interface{} {
		var result []byte

		// งาน CPU-intensive ที่ใช้ payload

		return result
	})
	defer pool.Close()

	http.HandleFunc("/work", func(w http.ResponseWriter, r *http.Request) {
		input, err := ioutil.ReadAll(r.Body)
		if err != nil {
			http.Error(w, "Internal error", http.StatusInternalServerError)
		}
		defer r.Body.Close()

		// นำงานเข้าไปใน pool ของเรา การเรียกใช้นี้จะเป็นการทำงานแบบเสถียรและจะ block จนกว่างานจะเสร็จสิ้น
		result := pool.Process(input)

		w.Write(result.([]byte))
	})

	http.ListenAndServe(":8080", nil)
}

Tunny ยังรองรับการตั้งเวลาหมดเวลา คุณสามารถแทนที่การเรียกใช้ Process ด้านบนด้วยโค้ดต่อไปนี้:

result, err := pool.ProcessTimed(input, time.Second*5)
if err == tunny.ErrJobTimedOut {
	http.Error(w, "Request timed out", http.StatusRequestTimeout)
}

คุณสามารถใช้ context ของคำขอ (หรือ context อื่น) เพื่อจัดการเวลาหมดเวลา และเวลาตามกำหนด Simply แทน Process ด้วยโค้ดต่อไปนี้:

result, err := pool.ProcessCtx(r.Context(), input)
if err == context.DeadlineExceeded {
	http.Error(w, "Request timed out", http.StatusRequestTimeout)
}

การปรับแต่งขนาดของ Pool

คุณสามารถใช้ SetSize(int) เพื่อเปลี่ยนขนาดของ Tunny pool ได้ทุกเมื่อ

pool.SetSize(10) // 10 goroutines
pool.SetSize(100) // 100 goroutines

นี้ปลอดภัยแม้ว่า goroutines ที่เหลืออยู่จะยังคงประมวลผล

การทำงานของ Goroutine ที่มีสตรีมของการทำงาน

บางครั้ง แต่ละ goroutine ใน Tunny pool ต้องมีสถานะการจัดการของตัวเอง ในกรณีนี้ คุณควรสร้าง tunny.Worker ซึ่งรวมถึงการเรียกรอให้สิ้นสุด ห้าม (หากงานหมดเวลาและไม่ได้ต้องการ), และบล็อกการจัดสรรงานที่ต่อมาจนกว่าเงื่อนไขบางประการกำหนดจะถูกตอบสนอง

เมื่อสร้าง pool ด้วยชนิด Worker คุณต้องให้ค่าสร้างเป็นแบบกำหนดเองของคุณ:

pool := tunny.New(poolSize, func() Worker {
	// งานการจัดสร้างสำหรับแต่ละ goroutine ที่นี่
	return newCustomWorker()
})

ดีอย่างนั้น Tunny สามารถทำความสะอาดการสร้างและการทำลายของชนิด Worker เมื่อขนาดของ pool มีการเปลี่ยนแปลง

การเรียงลำดับ

งานที่ค้างคงไว้ (backlogged jobs) ไม่สามารถคาดการณ์ได้ว่าจะถูกประมวลผลตามลำดับ เนื่องจากการสร้างปัจจุบันของช่องและการเลือกบล็อค ลำดับงานที่ค้างไว้จะถูกประมวลตาม FIFO queue แต่พฤติกรรมนี้ไม่ได้อยู่ในสเปคและไม่ควรให้การพฤติกรรมลำดับขึ้นอยู่กับมัน