【golang】 如何停止向一个已经closed的channel发送数据

golang中向一个closed的channel中发送数据,会造成严重“事故”。也是容易犯的常见毛病。

  1. 错误示范:
package main

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

var mu sync.Mutex
var isChanClosed = false

func setClosedFlag() {
	mu.Lock()
	isChanClosed = true
	mu.Unlock()
}

func getClosedFlag() bool {
	mu.Lock()
	defer mu.Unlock()
	return isChanClosed
}

func main() {

	ch := make(chan int, 10)
	//write
	go func() {
		for i := 0; i < 20; i++ {
			flag := getClosedFlag()
			if flag == true {
				return
			}
			fmt.Println(" before write isChanClosed:", flag)
			ch <- i
			time.Sleep(time.Millisecond * 100)
		}

		fmt.Println(" not write.....")
	}()

	//read
	go func() {
		for {
			time.Sleep(time.Millisecond * 500)
			m, ok := <-ch
			if ok {
				fmt.Println("channel not closed m=", m)
			} else {
				fmt.Println("channel closed, left elem's len:", len(ch))
				for m := range ch {
					fmt.Println("  left:  %d", m)
				}

			}
		}

	}()

	time.Sleep(5 * time.Second)

	setClosedFlag()
	close(ch)
	fmt.Println(">>>>> closed channel,  isChanClosed:", getClosedFlag())
	time.Sleep(time.Second * 300)
}

运行后:

根据flag 判断条件,write 之前是false 没有关闭, write时 channel 关闭了。报错。感觉 根据flag来判断还是“慢“了点。


一种解决方案: 使用select  ,并将write 功能 放在 default 分支中。


func main() {

	ch := make(chan int, 10)
	stop := make(chan bool)
	//write
	go func() {
		for {
			select {
			case <-stop:
				fmt.Println("ch closed. stop receive data")
				return

			default:
			 
				for i := 0; i < 20; i++ {
					flag := getClosedFlag()
					if flag == true {
						return
					}
					fmt.Println(" before write isChanClosed:", flag)
					ch <- i
					time.Sleep(time.Millisecond * 100)
				}
				fmt.Println(" not write.....")

			}
		}
	}()

	//read
	go func() {
		for {
			time.Sleep(time.Millisecond * 500)
			m, ok := <-ch
			if ok {
				fmt.Println("channel not closed m=", m)
			} else {
				fmt.Println("channel closed, left elem's len:", len(ch))
				for m := range ch {
					fmt.Println("  left:  %d", m)
				}
			}
		}
	}()

	time.Sleep(5 * time.Second)
	stop <- true
	close(ch)
	fmt.Println(">>>>> closed channel,  isChanClosed:", getClosedFlag())
	time.Sleep(time.Second * 300)
}

 运行结果:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值