踩到了goroutine暴增导致导致服务器死机的坑,因此我尝试限制goroutine并行个数。基本思路是用channel来控制并行个数和最大队列个数。
不做限制的代码是这样的:
package main
import (
"time"
"fmt"
"runtime"
)
func main(){
// 定义一个运行时间为1秒的方法
oneSecond := func(i int){
time.Sleep(1e9)
fmt.Println(i)
}
for i:=0; i<10 ;i++ {
go oneSecond(i)
}
for runtime.NumGoroutine()>1 {
time.Sleep(1e9)
}
}
上述代码,运行结果是所有内容一起输出,因此是所有goroutine同时运行的。
channel的限制原理是,定义一个n长度的chan,如果能向chan推入内容,则运行代码,否则阻塞。下面是一个简易的封装:
package main
import (
"time"
"fmt"
"runtime"
)
func main(){
// 定义一个运行时间为1秒的方法
oneSecond := func(i int){
time.Sleep(1e9)
fmt.Println(i)
}
n := 3 // n限制一次可以运行多少个
s := make(chan bool,n)
for i:=0; i<10 ;i++ {
s<-true
go func(i int){
oneSecond(i)
<-s
}(i)
}
for runtime.NumGoroutine()>1 {
time.Sleep(1e9)
}
}
这次的输出结果是每次输出n个数字,直到运行结束。
最后为了使用方便,我对这个限制进一步封装:
package main
import (
"time"
"fmt"
"runtime"
)
/******** 封装部分开始 *******/
type Gos struct{
s chan bool
f chan func() // 待执行的func队列
}
func NewGos(n int,m int)*Gos{
g := new(Gos)
g.s = make(chan bool,n) // 限制并行的goroutine最多n个,超过则本次func会排队
g.f = make(chan func(),m) // 限制排队的func最多m个,超过则外部调用的地方会阻塞
return g
}
func(g *Gos) Run(x func()){
select{
case g.s<-true: go func(){
x()
<-g.s
select{
default:
case x := <-g.f: g.Run(x)
}
}()
default: g.f<-x
}
}
/******** 封装部分结束 *******/
func main(){
// 定义一个运行时间为1秒的方法
oneSecond := func(i int){
time.Sleep(1e9)
fmt.Println(i)
}
s := NewGos(3,10)
for i:=0; i<10 ;i++ {
func(i int){
s.Run(func(){ oneSecond(i) })
}(i)
}
for runtime.NumGoroutine()>1 {
time.Sleep(1e9)
}
}
以上
相关文档
暂无
随便看看
畅言模块加载中