ถูกใจสาย Go สร้าง Concurrency limiting goroutine pool ด้วย workerpool แบบเข้าใจง่าย ๆ

Sharing is caring!

สวัสดีทุกท่าน ที่ยังคงติดตาม poolsawat.com ตลอดมา การเรียนรู้ที่ไม่มีวันสิ้นสุด สำหรับทุกคนที่มีนิสัยสอบเรียนรู้ อยู่ตลอดเวลา วันนี้จะพามาทำความรู้จักกับ workerpool การทำงานที่จะรีดประสิทธิภาพการทำงานของ CPU, Mem เพิ่มขึ้น ผลที่ได้คือย่นระยะเวลาการทำงานให้สั้นลง

สมมุติมีสถานะการการทำงานที่ต้องเขียนโปรแกรมเพื่อสร้างระบบ batch เพื่อประมวลผลที่ยาวนานมาก ๆ อาจจะเป็นด้วยเรื่องปริมาณของข้อมูลที่เยอะมาก ๆ หรือปัจจัยอื่น ๆ ที่ทำให้ระยะเวลาในการประมวลผลนาน การทำงานแบบ Parallel อาจจะตอบโจทย์ของปัญหานี้

gammazero/workerpool คืออะไร

การจำกัดพูล goroutine จำกัดการทำงานพร้อมกันของงาน ไม่ใช่จำนวนงานที่อยู่ในคิว ไม่บล็อกการส่งงาน ไม่ว่าจะคิวงานกี่งานก็ตาม กล่าวง่าย ๆ คือ การทำงานที่พร้อมกันแบบกำหนดจำนวนได้ และค่อยเติมคิวงานที่เหลือจนกว่าจะหมดคิวงาน

ตัวอย่างโค๊ดการใช้งาน

ก่อนอื่นก็ต้องเพิ่ม dependency

go get github.com/gammazero/workerpool

โค๊ดตัวอย่างการทำงาน

func main() {

	wp := workerpool.New(2)
	requests := []string{"alpha", "beta", "gamma", "delta", "epsilon"}

	for _, r := range requests {
		r := r
		t := 5
		wp.Submit(func() {
			time.Sleep(time.Duration(t) * time.Second)
			fmt.Printf("%s every for %d second: %s\n", time.Now(), t, r)
		})
	}

	wp.StopWait()
}

ผลลัพธ์

2024-03-23 20:12:01.8476281 +0700 +07 m=+5.008092201 every for 5 second: alpha
2024-03-23 20:12:01.8475082 +0700 +07 m=+5.007972301 every for 5 second: beta
2024-03-23 20:12:06.8511684 +0700 +07 m=+10.011632501 every for 5 second: delta
2024-03-23 20:12:06.8511684 +0700 +07 m=+10.011632501 every for 5 second: gamma
2024-03-23 20:12:11.8539056 +0700 +07 m=+15.014369701 every for 5 second: epsilon

กำหนดการทำงานที่พร้อมกัน 2 การทำงาน ในแต่ละการทำงาน จะใช้เวลาประมวลผล 5 วินาที เมื่อการทำงานเสร็จและจะประมวลผลการทำงานของงานคิวถัด ๆ ไป จนกว่าจะเสร็จสิ้นทุกงาน

นอกจากฟังก์ชั่นการทำงานหลักอย่าง Submit ของ worker ยังมีฟังก์ชั่นอื่น ๆ ที่น่าสนใจ เพิ่มเติม เช่น WaitingQueueSize() ที่สามารถบอกคิวงานที่เหลือใน worker pool

เพิ่มโค๊ดแสดงคิวงานคงเหลือใน workerpool

 go func() {
	for range time.Tick(time.Second * 2) {
		fmt.Printf("WaitingQueueSize :=%d\n", wp.WaitingQueueSize())
	}
}()

ผลลัพธ์

WaitingQueueSize :=3
WaitingQueueSize :=3
2024-03-23 20:29:40.499205 +0700 +07 m=+5.003341801 every for 5 second: alpha
2024-03-23 20:29:40.4990055 +0700 +07 m=+5.003142301 every for 5 second: beta
WaitingQueueSize :=1
WaitingQueueSize :=1
WaitingQueueSize :=1
2024-03-23 20:29:45.5067569 +0700 +07 m=+10.010893701 every for 5 second: delta
2024-03-23 20:29:45.5069241 +0700 +07 m=+10.011060901 every for 5 second: gamma
WaitingQueueSize :=0
WaitingQueueSize :=0
2024-03-23 20:29:50.5117773 +0700 +07 m=+15.015914101 every for 5 second: epsilon

สรุปท้ายบทความ

ไม่ยากเลยใช่ไหมครับ ข้อดีของการเลือกใช้งาน dependency จากภายนอก แทนที่จะเขียนเอง เพราะมีปัญหาต่าง ๆ ที่ถูกแก้ไข และมีตัวอย่างโค๊ด สำหรับการเลือก dependency จะดูที่ github star ตัวเลขยิ่งมาก แสดงว่ามีคนใช้งานมาก อย่างน้อยก็ไม่ได้มีเพียงแค่เราใช้งานอยู่คนเดียว เวลามีปัญหา จะมีตัวอย่างการแก้ไข หรือไปโพสต์หัวข้อคำถามไว้

เมื่อได้ลองนำ workerpool มาใช้งาน เหตุผลหลัก ๆ คือกระจายการทำงานได้ ย่นเวลาการทำงานลงได้ แต่ก็ต้องดูปัจจัยอื่น ๆ เพิ่มเติมด้วย เช่น CPU, Mem, หรือแม้แต่การรับโหลดของ API หรือ Database ประกอบด้วย สำหรับบาความนี้ขอฝากไว้เท่านี้ครับ

ใส่ความเห็น

อีเมลของคุณจะไม่แสดงให้คนอื่นเห็น ช่องข้อมูลจำเป็นถูกทำเครื่องหมาย *