golang - 控制协程并发数的3种方法

在golang中使用协程非常方便,如果有大量任务要处理,且任务间没有关联,可以并行同时处理的话,就非常适合用golang的协程处理。串行一个个执行需要的效率,远没有并行同时处理来的快,特别是当处理每个任务需要的时间越长,使用并行效果就越明显。


是的,golang就是利用多核cpu的云时代语言。


有些时候,golang起的协程特别多的话,机器的性能或其他服务组件会扛不住,比如服务器IO,数据库连接等,这时候需要主动控制协程并发数,避免服务崩溃。
下面是golang控制协程并发数的几种方法,很有意思。


代码实践:
方法一:使用有缓冲容量长度的channel控制

package main

import (
	"fmt"
	"time"
)

//同时最多10个协程运行
var limitMaxNum = 10
var chData = make(chan int, limitMaxNum)

//有100个任务要处理
var tasknum = 100

//使用 有缓冲容量长度的channel
func main() {
	var i, j int
	var chanRet = make(chan int, tasknum) //运行结果存储到chanRet

	//运行处理
	go func() {
		for i = 0; i < tasknum; i++ {
			chData <- 1
			go dotask(i, chanRet)
		}
	}()

	//获取返回结果
	for j = 0; j < tasknum; j++ {
		<-chData
		<-chanRet
		// fmt.Println("ret:", ret)
	}
	fmt.Println("main over")
}

func dotask(taskid int, chanRet chan int) {
	time.Sleep(time.Millisecond * 100)
	fmt.Println("finish task ", taskid)

	chanRet <- taskid * taskid
}


应用场景:适合知道任务数量,最简单的使用方式。



方法2:使用channel+waitGroup

package main

import (
	"fmt"
	"sync"
	"time"
)

var limitMaxNum = 10
var chData = make(chan int, limitMaxNum)
var jobGroup sync.WaitGroup
var tasknum = 100

//使用 有缓冲容量长度的channel
func main() {
	var i int
	//var chanRet = make(chan int, tasknum)

	//处理任务,最多同时有10个协程
	for i = 0; i < tasknum; i++ {
		chData <- 1
		go dotask(i)
	}

	//使用Wait等待所有任务执行完毕
	jobGroup.Wait()
	fmt.Println("main over")
}

func dotask(taskid int) {
	jobGroup.Add(1)

	time.Sleep(time.Millisecond * 100)
	fmt.Println("finish task ", taskid)

	// fmt.taskid * taskid
	<-chData

	jobGroup.Done()
}


应用场景:waitGroup开箱即用,不管任务数量是否提前清楚的情况下,都可以用,也很简单,少了次循环。


方法3:优雅使用waitGroup+channel+range

package main

import (
	"fmt"
	"sync"
	"time"
)

var limitMaxNum = 10
var chData = make(chan int, limitMaxNum)
var jobGroup sync.WaitGroup
var tasknum = 100

func main() {
	var i int
	var j int

	//组装任务
	chanTask := make(chan int, tasknum)
	for j = 0; j < tasknum; j++ {
		chanTask <- j
	}
	close(chanTask)

	jobGroup.Add(tasknum)
	for i = 0; i < limitMaxNum; i++ { //最多10个协程
		go dotask3(chanTask)
	}

	jobGroup.Wait()
	fmt.Println("main over")
}

func dotask3(taskChan chan int) {
	for taskid := range taskChan { //每个协程拼命抢夺任务,直到任务完结
		time.Sleep(time.Millisecond * 500)
		fmt.Println("finish task ", taskid)
		jobGroup.Done()
	}
}


应用场景:这个处理方式最优雅,不仅控制了同时运行的只有10个协程,而且整个运行过程中只起了10个协程(当然不包括主协程),处理方式也很优雅,高效利用了channel 是否阻塞特点,最推荐这个。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值