• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

NilChannelsAlwaysBlock(Go语言中空管道总是阻塞)

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

译自:https://www.godesignpatterns.com/2014/05/nil-channels-always-block.html 

原作者:Alex Lockwood

  在本篇文章中,我们将讨论 nil channel 在 Go 中的使用。nil channel 无论是接收还是发送都会永久阻塞:

// Create an uninitialized (nil) channel.
var ch chan struct{}

// Receiving on a nil channel blocks forever.
<-ch

// Sending on a nil channel will also block forever.
ch <- struct{}{}

  nil channel 看上去似乎没有什么用,甚至曾经在你的项目中引起 bug(例如忘记在使用 channels 前,用 make 初始化)。但是,可以通过几种巧妙的方式利用此属性,特别是当你需要在 select 语句中动态禁用一个 case:

if disableSelectCase {
	ch1 = nil
} else {
	ch1 = nonNilChan
}

select {
case <-ch1:
	// This case will only be considered if ch1 is not nil.
// 这个 case 直到 ch1 不是 nil 时才会被考虑 case <-ch2: // This case will always be considered (assuming ch2 is non-nil). }

  上面的 code 阐明了这样一个特征,当 select 语句中的一个case 是 nil channel 时,它将会选择性忽略。如果 boolean 类型的 disableSelectCase 为 true ,此时会将 nil 赋值给 ch1,从而阻止 ch1 channel 被 select 语句考虑。

  这种特性也被用来防止空循环,比如当你需要等待多个 channels 关闭时:

// WARNING! Spin loop might occur!
var isClosed1, isClosed2 bool
for !isClosed1 || !isClosed2 {
	select {
	case _, ok := <-ch1:
		if !ok {
			isClosed1 = true
		}
	case _, ok := <-ch2:
		if !ok {
			isClosed2 = true
		}
	}
}

  如果上面的代码中两个 channel 有一个被关闭,将会在你的项目中引起一个小 bug。因为被关闭的 channel 永远不会阻塞,如果 ch1 被关闭,ch1 在随后的循环迭代中将总是准备被接收。作为结果,程序将陷入死循环,还有就是 case <- ch2 也许再也没有机会被执行。

  为了解决这个问题,我们可以利用 nil channel 总是阻塞的特性:

// Safely disable channels after they are closed.
for ch1 != nil || ch2 != nil {
	select {
	case _, ok := <-ch1:
		if !ok {
			ch1 = nil
		}
	case _, ok := <-ch2:
		if !ok {
			ch2 = nil
		}
	}
}

  


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
兼容gorediscluster的pipeline批量发布时间:2022-07-10
下一篇:
GoRuntimehashmap实现发布时间:2022-07-10
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap