Go协程池设计思路(Task-Job-Worker)
1. 鋪墊:Go 的接收器Receiver
在go語言中,沒有類的概念,但是可以給類型(結構體,自定義類型)定義方法。所謂方法就是定義了接受者的函數。接受者定義在func關鍵字和函數名之間。可以理解成為結構體定義函數方法,類似于C++中的類方法。
type Person struct {name stringage int }func (p Person) say() {fmt.Printf("I'm %s,%d years old\n",p.name,p.age) }接受者類型可以是struct,也可以是指向struc的指針。
- 接收者的類型為struct
output:
I'm lineshen,25 years old I'm leleyue,22 years old對于p1的調用,是沒有問題的,因為傳遞的是結構體,在方法中改變結構體屬性,并不能改變原來內存中的值。
對于p2的調用會產生疑問,p2明明是個指針,為什么再調用了older方法之后,打印結果還是22 years old?
方法的接受者是Person而調用者是*Person。其實在p2調用時存在一個轉換p2.older() -> *p2.older(); p2.say() -> *p2.say()
p2是指向Person實例的指針。因此,方法執行時的接受者實際上還是一個值而非引用,因此值是不會發生改變的。
- 接收者的類型為指針
output:
I'm lineshen,26 years old I'm leleyue,23 years old此時傳遞的是引用,并非值。因此,結構體在內存中屬性值會跟隨函數方法發生相應的改變。
2. 正題:協程池的設計思路
類似于淘寶電商,可能每分鐘有百萬級別的請求,最簡單直觀的方法是來一個請求,new goroutine處理這個請求;那么需要的goroutine也是百萬級別的。這樣做業務處理邏輯是清楚了,但是會導致CPU做很多無用功,因為CPU需要在不同的goroutin之間流轉。所以,在實際業務中,應該限制gorotine的個數(一般協程的數量與CPU的數量保持一致,加大CPU的利用率)。一個可行的架構設計如下:
示例代碼如下:
package main import ("fmt""time")// 任務的屬性應該是一個業務函數 type Task struct {f func() error // 函數名f, 無參,返回值為error }// 創建Task任務 func NewTask(arg_f func() error) *Task {task := Task{f: arg_f,}return &task }// Task綁定業務方法 func (task *Task) Execute() {task.f() // 調用任務中已經綁定好的業務方法 }// ------------------------------------------------ type Pool struct {EntryChannel chan *Task // 對外的Task入口JobsChannel chan *Task // 內部的Task隊列workerNum int // 協程池中最大的woker數量 }// 創建Pool func NewPool(cap int) *Pool {pool := Pool {EntryChannel : make(chan *Task),JobsChannel : make(chan *Task),workerNum : cap,}return &pool }// Pool綁定干活的方法 func (pool *Pool) worker(workID int) {// worker工作 : 永久從JobsChannel取任務 然后執行任務for task := range pool.JobsChannel {task.Execute()fmt.Println("work ID ", workID, " has executed")} }// Pool綁定協程池工作方法 func (pool *Pool) run() {// 定義worker數量for i:=0; i<pool.workerNum; i++ {go pool.worker(i)}// 從EntryChannel去任務,發送給JobsChannelfor task := range pool.EntryChannel {pool.JobsChannel <- task // 添加task優先級排序邏輯} }// ------------------------------------------------ func main() {// 創建一些任務task := NewTask( func() error { // 匿名函數fmt.Println(time.Now())return nil})// 創建協程池pool := NewPool(4)// 創建多任務,拋給協程池 go func() { // 開啟新的協程,防止阻塞for{pool.EntryChannel <- task}}()// 啟動協程池pool.run() }output:
work ID 0 has executed 2020-04-13 00:15:28.6042081 +0800 CST m=+0.040858901 work ID 0 has executed 2020-04-13 00:15:28.605204 +0800 CST m=+0.041854801 work ID 0 has executed 2020-04-13 00:15:28.6062025 +0800 CST m=+0.042853301 work ID 0 has executed 2020-04-13 00:15:28.6062025 +0800 CST m=+0.042853301 work ID 0 has executed 2020-04-13 00:15:28.6071987 +0800 CST m=+0.043849501 work ID 0 has executed 2020-04-13 00:15:28.6071987 +0800 CST m=+0.043849501 work ID 0 has executed 2020-04-13 00:15:28.6081959 +0800 CST m=+0.044846701 work ID 0 has executed 2020-04-13 00:15:28.6081959 +0800 CST m=+0.044846701 work ID 0 has executed 2020-04-13 00:15:28.6091933 +0800 CST m=+0.045844101 work ID 0 has executed 2020-04-13 00:15:28.6091933 +0800 CST m=+0.045844101 work ID 0 has executed 2020-04-13 00:15:28.6101907 +0800 CST m=+0.046841501 work ID 0 has executed 2020-04-13 00:15:28.6101907 +0800 CST m=+0.046841501 work ID 0 has executed 2020-04-13 00:15:28.6101907 +0800 CST m=+0.046841501 work ID 0 has executed 2020-04-13 00:15:28.6111882 +0800 CST m=+0.047839001 work ID 0 has executed 2020-04-13 00:15:28.5683041 +0800 CST m=+0.004954901 work ID 1 has executed 2020-04-13 00:15:28.5673053 +0800 CST m=+0.003956101 work ID 3 has executed 2020-04-13 00:15:28.6121853 +0800 CST m=+0.048836101 work ID 3 has executed 2020-04-13 00:15:28.6121853 +0800 CST m=+0.048836101 work ID 3 has executed 2020-04-13 00:15:28.6121853 +0800 CST m=+0.048836101 work ID 3 has executed 2020-04-13 00:15:28.5673053 +0800 CST m=+0.003956101 work ID 2 has executed 2020-04-13 00:15:28.6151779 +0800 CST m=+0.051828701 work ID 2 has executed 2020-04-13 00:15:28.6151779 +0800 CST m=+0.051828701 work ID 2 has executed 2020-04-13 00:15:28.6161747 +0800 CST m=+0.052825501 work ID 2 has executed 2020-04-13 00:15:28.6161747 +0800 CST m=+0.052825501 work ID 2 has executed 2020-04-13 00:15:28.6171731 +0800 CST m=+0.053823901 work ID 2 has executed 2020-04-13 00:15:28.6171731 +0800 CST m=+0.053823901 work ID 2 has executed 2020-04-13 00:15:28.6181705 +0800 CST m=+0.054821301 work ID 2 has executed 2020-04-13 00:15:28.6181705 +0800 CST m=+0.054821301 work ID 2 has executed 2020-04-13 00:15:28.6181705 +0800 CST m=+0.054821301 work ID 2 has executed 2020-04-13 00:15:28.6181705 +0800 CST m=+0.054821301 work ID 2 has executed 2020-04-13 00:15:28.6191668 +0800 CST m=+0.055817601 work ID 2 has executed 2020-04-13 00:15:28.6191668 +0800 CST m=+0.055817601 work ID 2 has executed 2020-04-13 00:15:28.6191668 +0800 CST m=+0.055817601 work ID 2 has executed 2020-04-13 00:15:28.6191668 +0800 CST m=+0.055817601 work ID 2 has executed 2020-04-13 00:15:28.6201639 +0800 CST m=+0.056814701 work ID 2 has executed 2020-04-13 00:15:28.6111882 +0800 CST m=+0.047839001 work ID 0 has executed 2020-04-13 00:15:28.6201639 +0800 CST m=+0.056814701 work ID 0 has executed 2020-04-13 00:15:28.6211612 +0800 CST m=+0.057812001 work ID 0 has executed 2020-04-13 00:15:28.6201639 +0800 CST m=+0.056814701 work ID 2 has executed 2020-04-13 00:15:28.6221586 +0800 CST m=+0.058809401 work ID 2 has executed 2020-04-13 00:15:28.6221586 +0800 CST m=+0.058809401 work ID 2 has executed 2020-04-13 00:15:28.6251574 +0800 CST m=+0.061808201 work ID 2 has executed 2020-04-13 00:15:28.6261523 +0800 CST m=+0.062803101 work ID 2 has executed 2020-04-13 00:15:28.6261523 +0800 CST m=+0.062803101 work ID 2 has executed 2020-04-13 00:15:28.6271454 +0800 CST m=+0.063796201 work ID 2 has executed 2020-04-13 00:15:28.6271454 +0800 CST m=+0.063796201 work ID 2 has executed 2020-04-13 00:15:28.6281435 +0800 CST m=+0.064794301 work ID 2 has executed 2020-04-13 00:15:28.6281435 +0800 CST m=+0.064794301 work ID 2 has executed 2020-04-13 00:15:28.6291399 +0800 CST m=+0.065790701 work ID 2 has executed 2020-04-13 00:15:28.6291399 +0800 CST m=+0.065790701 work ID 2 has executed 2020-04-13 00:15:28.6301372 +0800 CST m=+0.066788001 work ID 2 has executed 2020-04-13 00:15:28.6301372 +0800 CST m=+0.066788001 work ID 2 has executed 2020-04-13 00:15:28.6142098 +0800 CST m=+0.050860601 work ID 3 has executed 2020-04-13 00:15:28.6311355 +0800 CST m=+0.067786301 work ID 3 has executed 2020-04-13 00:15:28.6321319 +0800 CST m=+0.068782701 work ID 3 has executed 2020-04-13 00:15:28.6321319 +0800 CST m=+0.068782701 work ID 3 has executed 2020-04-13 00:15:28.6331302 +0800 CST m=+0.069781001 work ID 3 has executed 2020-04-13 00:15:28.6331302 +0800 CST m=+0.069781001 work ID 3 has executed 2020-04-13 00:15:28.6331302 +0800 CST m=+0.069781001 work ID 3 has executed 2020-04-13 00:15:28.6391157 +0800 CST m=+0.075766501 work ID 3 has executed學習視頻:https://www.bilibili.com/video/BV1cx41197j5?from=search&seid=15155039435359774234
總結
以上是生活随笔為你收集整理的Go协程池设计思路(Task-Job-Worker)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何将多个文件捆绑成一个可执行文件
- 下一篇: 喜欢一个不喜欢自己的人是痛苦的!