package main
import (
"context"
"fmt"
"time"
)
func Task () {
ctx,_:=context.WithTimeout(context.Background(),time.Second*1)
check :=make(chan struct{})
go func() {
time.Sleep(time.Millisecond*1200)
check<- struct{}{}
}()
select {
case <-check:
fmt.Println("未超时")
case <-ctx.Done():
fmt.Println("超时了")
}
}
func main() {
for i:=0;i<=20;i++ {
go Task()
}
for {
}
}
此程序会造成什么后果?
在main方法中添加如下代码
func main() {
for i:=0;i<=20;i++ {
go Task()
}
for {
time.Sleep(time.Second*2)
fmt.Println(runtime.NumGoroutine())
}
}
输出结果
可以看到运行中协程数量一直维持在22造成内存泄露。
原因是定义管道check的时候是无缓存的所以在程序超时时check无法处理,外层task结束而里面go协程继续等待,协程无法释放一直占用内存导致内存泄露。修改方法如下:
func Task () {
ctx,_:=context.WithTimeout(context.Background(),time.Second*1)
//增加一个缓存区
check :=make(chan struct{},1)
go func() {
time.Sleep(time.Millisecond*1200)
check<- struct{}{}
}()
select {
case <-check:
fmt.Println("未超时")
case <-ctx.Done():
fmt.Println("超时了")
}
}
无缓冲channel和有缓存channel区别:
c1:=make(chan int) 无缓冲
c2:=make(chan int,1) 有缓冲
c1<-1
无缓冲的 不仅仅是 向 c1 通道放 1 而是 一直要有别的携程 <-c1 接手了 这个参数,那么c1<-1才会继续下去,要不然就一直阻塞着
而 c2<-1 则不会阻塞,因为缓冲大小是1 (其实是缓冲大小为0)只有当 放第二个值的时候 第一个还没被人拿走,这时候才会阻塞。