案例:
func send(ch chan<- int,exit chan struct{}) { for i := 0; i < 10; i++ { ch <- i fmt.Println("输入",i) } close(ch) var a struct{} exit <- a } func get(ch <-chan int,exit chan struct{}) { for i := 0; i < 10; i++ { v,ok := <-ch if !ok { break } fmt.Println("输出",v) } var a struct{} exit <- a } func main() { ch := make(chan int ,10) //双向通道 exitChan := make(chan struct{} ,2) go send(ch,exitChan) go get(ch,exitChan) for { if len(exitChan) == 2 { break } } }可以使用for+select语句防止阻塞:
func main() { ch := make(chan int ,10) for i := 0; i < 5; i++ { ch <- i } ch2 := make(chan float64 ,10) for i := 0; i < 5; i++ { ch2 <- rand.Float64() } label: for { select { case n:= <-ch: fmt.Println(n) time.Sleep(time.Second) case m:=<-ch2: fmt.Println(m) time.Sleep(time.Second) default: fmt.Println("没了") time.Sleep(time.Second) //return 直接结束退出程序运行 break label //中断指定的 for 循环 } } }使用defer+recover解决运行时协程中抛出的panic,保证程序继续运行:
func wrong() { defer func(){ if e := recover() ; e != nil { fmt.Print("func wrong()计算错误,") fmt.Println("异常",e) } }() num := 0 num1 := 100 num = num1 /num fmt.Println("func wrong()计算正确",num) } func right() { defer func(){ if e := recover() ; e != nil { fmt.Println(e) } }() num := 10 num1 := 100 num = num1 /num fmt.Println("func right() 计算正确",num) } func main() { go wrong() go right() for i := 0; i < 5; i++ { time.Sleep(time.Second) i++ } }关于recover:
内建函数recover允许程序管理恐慌过程中的Go程。在defer的函数中,执行recover调用会取回传至panic调用的错误值,恢复正常执行,停止恐慌过程。若recover在defer的函数之外被调用,它将不会停止恐慌过程序列。在此情况下,或当该Go程不在恐慌过程中时,或提供给panic的实参为nil时,recover就会返回nil。