0%

控制gorutine并发数量

控制并发数量可以避免服务器奔溃:以下方式尝试控制

注意:多个并发协程之间不需要通信,那么就可以使用 sync.WaitGroup

如果并发启动了多个子协程,需要等待所有的子协程完成任务,WaitGroup 非常适合于这类场景

  • 只是用Chan控制
package main

import (
   "fmt"
)

//控制并发数量 chan
func main() {
   count := 10
   ch := make(chan bool, 2)
   for i := 0; i < count; i++ {
      ch <- true
      go read(ch, i)
   }
   //time.Sleep(time.Second * 2)
}
func read(ch chan bool, i int) {
   fmt.Println("第", i, "个协程",time.Now().Unix())
   //为了测试并发数量
   time.Sleep(time.Second)
   <-ch
}
/* 以下为输出---(应该输出10个)
第 1 个协程 1663071133
第 0 个协程 1663071133
第 2 个协程 1663071134
第 3 个协程 1663071134
第 4 个协程 1663071135
第 5 个协程 1663071135
第 6 个协程 1663071136
第 7 个协程 1663071136
第 8 个协程 1663071137
*/

出现问题:看似达到控制2个2个输出的效果,但是主协程结束时,子协程也是会被终止掉的,因此剩余的 goroutine 没来及把值输出,

  • 只使用Sync.WaitGroup
// Sync控制
var wg sync.WaitGroup

func main() {
	count := 10
	for i := 0; i < count; i++ {
		wg.Add(1)
		go read(i)
	}
	wg.Wait()
}
func read(i int) {
	defer wg.Done()
	fmt.Println("第", i, "个协程", time.Now().Unix())
    //为了测试并发数量
    time.Sleep(time.Second)
}
/* 以下为输出---(应该输出10个)
第 9 个协程 1663070879
第 4 个协程 1663070879
第 2 个协程 1663070879
第 3 个协程 1663070879
第 0 个协程 1663070879
第 6 个协程 1663070879
第 5 个协程 1663070879
第 7 个协程 1663070879
第 8 个协程 1663070879
第 1 个协程 1663070879
*/

出现问题:没有达到控制2个2个输出的效果。

  • 使用Sync.WaitGroup+Chan
//Sync+Chan
var wg sync.WaitGroup

func main() {
	count := 10
	ch := make(chan bool, 2)
	for i := 0; i < count; i++ {
		wg.Add(1)
        ch <- true
		go read(ch, i)
	}
	wg.Wait()
}
func read(ch chan bool, i int) {
	defer wg.Done()
    //TODO
	//ch <- true 放在里面吃内存(待处理 )
	fmt.Println("第", i, "个协程", time.Now().Unix())
	//为了测试并发数量
	time.Sleep(time.Second)
	<-ch
}

/* 以下为输出---(应该输出10个)
第 1 个协程 1663071133
第 0 个协程 1663071133
第 2 个协程 1663071134
第 3 个协程 1663071134
第 4 个协程 1663071135
第 5 个协程 1663071135
第 6 个协程 1663071136
第 7 个协程 1663071136
第 8 个协程 1663071137
*/

成功:达到控制2个2个输出的效果。

新场景——控制输入的数量,以此达到改变允许并发运行 goroutine 的数量(灵活控制)

package main

import (
    "fmt"
    "sync"
    "time"
)
var wg sync.WaitGroup
var count int

func main() {
	userCount := 10
	ch := make(chan int, 5)
	for i := 0; i < userCount; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			for d := range ch {
				count++
				fmt.Println("第", count, "个协程", time.Now().Unix())
				time.Sleep(time.Second * time.Duration(d))
			}
		}()
	}

	for i := 0; i < 10; i++ {
		//输入几个ch 就有几个*userCount个协程
		ch <- 1
		ch <- 2
		ch <- 3
		//time.Sleep(time.Second)
	}

	close(ch)
	wg.Wait()
}

/* 以下为输出---(应该输出30个)
第 1 个协程 1663072405
第 2 个协程 1663072405 
第 4 个协程 1663072405 
第 5 个协程 1663072405 
第 6 个协程 1663072405 
第 7 个协程 1663072405 
第 8 个协程 1663072405 
第 9 个协程 1663072405 
第 10 个协程 1663072405
第 3 个协程 1663072405 
第 12 个协程 1663072406
第 13 个协程 1663072406
第 14 个协程 1663072406
第 11 个协程 1663072406
第 15 个协程 1663072407
第 16 个协程 1663072407
第 17 个协程 1663072407
第 18 个协程 1663072407
第 19 个协程 1663072408
第 20 个协程 1663072408
第 21 个协程 1663072408
第 22 个协程 1663072408
第 23 个协程 1663072408
第 24 个协程 1663072408
第 25 个协程 1663072409
第 26 个协程 1663072409
第 28 个协程 1663072409
第 27 个协程 1663072409
第 29 个协程 1663072410
第 30 个协程 1663072410
*/
-------------本文结束感谢您的阅读-------------
打赏一瓶矿泉水