# Golang 并发编程最佳实践

By [Robin](https://paragraph.com/@robin-8) · 2023-03-02

---

sync.WaitGroup
==============

    var wg sync.WaitGroup
    
    func f1(i int) {
        defer wg.Done()
        time.Sleep(time.Second * time.Duration(rand.Intn(5)))
        fmt.Println(i)
    }
    
    func main() {
    
        for i := 0; i < 10; i++ {
            wg.Add(1)
            go f1(i)
        }
        wg.Wait()
    }
    

channel
=======

    var wg sync.WaitGroup
    
    // 1. 启动一个goroutin 生成100个数发送到ch1
    func f1(ch1 chan int) {
        defer wg.Done()
        for i := 0; i < 100; i++ {
            ch1 <- i
        }
        close(ch1)
    }
    
    // 2. 启用一个routine，从ch1中取值，计算平方放到ch2
    func f2(ch1, ch2 chan int) {
        defer wg.Done()
        for {
            x, ok := <-ch1
            if !ok {
                break
            }
            ch2 <- x * x
        }
        close(ch2)
    
    }
    
    // 3. 在main中从ch2取值打印出来
    
    func main() {
        a := make(chan int, 50)
        b := make(chan int, 100)
        wg.Add(2)
        go f1(a)
        go f2(a, b)
        wg.Wait()
        for ret := range b {
            fmt.Println(ret)
        }
    }
    

线程池 goroutin-pool
=================

    var wg sync.WaitGroup
    
    func worker(id int, jobs <-chan int, results chan<- int) {
        defer wg.Done()
        fmt.Printf("worker:%d has started.\n", id)
        for j := range jobs {
            fmt.Printf("worker:%d start job:%d\n", id, j)
            time.Sleep(time.Second * 1)
            fmt.Printf("worker:%d end job:%d\n", id, j)
            results <- j * 2
        }
    }
    
    func main() {
        jobs := make(chan int, 100)
        results := make(chan int, 100)
    
        // 启动10个线程worker处理数据
        for w := 1; w <= 10; w++ {
            wg.Add(1)
            go worker(w, jobs, results)
        }
        time.Sleep(time.Second * 3)
        fmt.Println("All of workers have already started.")
    
        // 后台生成100个job任务
        go func() {
            for j := 1; j <= 100; j++ {
                jobs <- j
            }
            close(jobs)
        }()
        wg.Wait()
        fmt.Println("Finished all jobs.")
    }
    

典型使用场景
======

    // 使用goroutin和channel实现一个计算int64随机数各位和的程序
    // 1. 开启一个goroutin循环生成int64类型随机数，发送到jobChan
    // 2. 开启24个goroutin从jobChan中取出随机数计算各位的和，将结果发送到resultChan
    // 3. 主goroutine从resultChan中取出来结果并打印到终端
    
    var wg sync.WaitGroup
    
    type job struct {
        value int64
    }
    
    type result struct {
        job *job
        sum int64
    }
    
    var jobChan = make(chan *job, 100)
    var resultChan = make(chan *result, 100)
    
    func producer(jobs chan<- *job) {
        defer wg.Done()
        // 循环生成int64类型随机数，发送到jobChan
        for {
            x := rand.Int63()
            newJob := &job{
                value: x,
            }
            jobs <- newJob
            time.Sleep(time.Millisecond * 500)
        }
    }
    
    func consumer(jobs <-chan *job, r chan<- *result) {
        defer wg.Done()
        // 从jobChan中取出随机数计算各位的和，将结果发送到resultChan
        for {
            job := <-jobs
            sum := int64(0)
            n := job.value
            for n > 0 {
                sum += n % 10
                n = n / 10
            }
    
            newResult := &result{
                job: job,
                sum: sum,
            }
            resultChan <- newResult
    
        }
    }
    
    func main() {
        wg.Add(1)
        go producer(jobChan)
    
        wg.Add(24)
        for i := 0; i < 24; i++ {
            go consumer(jobChan, resultChan)
        }
    
        for result := range resultChan {
            fmt.Printf("value:%d sum:%d\n", result.job.value, result.sum)
        }
    
        wg.Wait()
    }

---

*Originally published on [Robin](https://paragraph.com/@robin-8/golang-7)*
