Implementing Goroutine Pool through Channel

Recent use of Go to import data from Excel into the server is for http requests
But there is a problem that new Goroutine will be added indefinitely after reading from the file.
Causes all cards to be stuck in the initialization request and then gets stuck.

Problem simulation

  • Simulation code
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()
}
  • If the number is small, it will be fine, but if the number is large, it will be found that the program is directly stuck for a period of time, then the error will be reported and no requests will be made.

Problem solving

  • In fact, it can be seen that too many HTTP requests should be initiated at the same time, causing the system to jam data and not send it.
  • When I think of submitting requests in Java with Thread, I think I can't limit the number of Goroutine s.
  • The use of powerful fruit to find the cooperating pool has been written by the big guys.
  • I added comments to the code as follows
package gopool

import (
    "sync"
)

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

// New Creates a New Cooperative Pool
func New(size int) *Pool {
    if size <= 0 {
        size = 1
    }
    return &Pool{
        queue: make(chan int, size),
        wg:    &sync.WaitGroup{},
    }
}

// Add a new execution
func (p *Pool) Add(delta int) {
    // If delta is positive, add it
    for i := 0; i < delta; i++ {
        p.queue <- 1
    }
    // When delta is negative, it decreases.
    for i := 0; i > delta; i-- {
        <-p.queue
    }
    p.wg.Add(delta)
}

// Done execution completion minus one
func (p *Pool) Done() {
    <-p.queue
    p.wg.Done()
}

// Wait waits for Goroutine to finish executing
func (p *Pool) Wait() {
    p.wg.Wait()
}
  • Then modify the test method just now.
package main

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

func main() {
    // Five concurrencies are limited here
    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()
}
  • Perfect solution

Keywords: Go Excel Java

Added by drucifer on Thu, 10 Oct 2019 03:20:03 +0300