經過 Channel 實現 Goroutine Pool

最近用到了 Go 從 Excel 導數據到服務器內部 用的是 http 請求
可是發現一個問題 從文件讀取以後 新開 Goroutine 會無限制新增
致使所有卡在初始化請求 因而乎就卡死了服務器

問題模擬

  • 模擬代碼
func main() {
    pool := sync.WaitGroup{}
    for i := 0; i < 500; i++ {
        pool.Add(1)
        go func(i int) {
            resp, err := http.Get("http://ip.3322.org")
            if err != nil {
                fmt.Println(i, err)
            } else {
                defer resp.Body.Close()
                result, _ := ioutil.ReadAll(resp.Body)
                fmt.Println(i, string(result))
            }
            pool.Done()
        }(i)
    }
    pool.Wait()
}
  • 數量小的狀況下 沒有問題 可是數量比較大的狀況 就會發現程序直接卡死 一段時間以後報錯 而且沒有發出任何請求

問題解決

  • 實際上看的出來 是應爲同時發起了太多的HTTP請求 致使系統卡死 數據沒有發送
  • 想到我在Java中用Thread提交請求 我就考慮 可不可限制 Goroutine 的數量
  • 使用強大的百度 果真找到了大佬已經寫好的協程池
  • 代碼以下 我加上了註釋
package gopool

import (
    "sync"
)

// Pool Goroutine Pool
type Pool struct {
    queue chan int
    wg    *sync.WaitGroup
}

// New 新建一個協程池
func New(size int) *Pool {
    if size <= 0 {
        size = 1
    }
    return &Pool{
        queue: make(chan int, size),
        wg:    &sync.WaitGroup{},
    }
}

// Add 新增一個執行
func (p *Pool) Add(delta int) {
    // delta爲正數就添加
    for i := 0; i < delta; i++ {
        p.queue <- 1
    }
    // delta爲負數就減小
    for i := 0; i > delta; i-- {
        <-p.queue
    }
    p.wg.Add(delta)
}

// Done 執行完成減一
func (p *Pool) Done() {
    <-p.queue
    p.wg.Done()
}

// Wait 等待Goroutine執行完畢
func (p *Pool) Wait() {
    p.wg.Wait()
}
  • 而後修改剛纔的測試方法
package main

import (
    "io/ioutil"
    "log"
    "net/http"
    "yumc.pw/cloud/lib/gopool"
)

func main() {
    // 這裏限制5個併發
    pool := gopool.New(5)// sync.WaitGroup{}
    for i := 0; i < 500; i++ {
        pool.Add(1)
        go func(i int) {
            resp, err := http.Get("http://ip.3322.org")
            if err != nil {
                fmt.Println(i, err)
            } else {
                defer resp.Body.Close()
                result, _ := ioutil.ReadAll(resp.Body)
                fmt.Println(i, string(result))
            }
            pool.Done()
        }(i)
    }
    pool.Wait()
}
  • 完美解決
相關文章
相關標籤/搜索