Golang实现Directional Channel(定向通道)

通道可以是定向的( directional )。在默认情况下,通道将以双向的( bidirectional )形式运作,用户既可以把值放人通道,也可以从通道取出值;但是,通道也可以被限制为只能执行发送操作( send-only )或者只能执行接收操作( receive-only )。

通常可以叫 定向通道 ,也有人叫 单向通道 ,两者其实都是指向这篇短文要讨论的 Directional Channel

下面直接举例子说明:

package onlyChannelTest

import (
	"fmt"
	"math/rand"
	"sync"
	"testing"
	"time"
)

func TestOnlyChannel(t *testing.T) {
	var wg sync.WaitGroup
	wg.Add(2)

	c:= make(chan int, 3)
	var send chan<- int = c
	var recv <-chan int = c

	go func() {
		defer wg.Done()
		for i := 0; i < 6; i++ {  // 注意这里是 6
			fmt.Print("receive\n")
			fmt.Println(<-recv)
		}
	}()

	go func() {
		defer wg.Done()
		defer close(c)

		rand.Seed(time.Now().UTC().UnixNano())
		for i := 0; i < 3; i++ {  // 这里是 3
			fmt.Print("send\n")
			send <- rand.Intn(100)
		}
	}()

	wg.Wait()
}

这里可以先猜一下运行结果,我直接贴出:

后面的引起了我的注意:

receive
0

是最让我困惑的地方,因为在一般印象内 channel 都是会阻塞的存在,而从上面结果看,第一个 recv 也是阻塞了)。但是后面的的 recv 却没有起到阻塞的作用,还是把 c 中的默认值 0 输出了。

通过 debug ,不难看出的是,两个单向通道的发送和接收都是从一个缓冲通道中进行操作的,两个单项通道同属于一个双向通道,只不过他们被分别限制了接收和发送功能。

通过 debug ,再次发现,在 recv 读取完之后,通道内并没有被 “清空” ,而是保有默认值。

难道, recv 并没有被阻塞?

验证方法如下:

// defer close(c)

选择注释掉发送 Goroutine 中的关闭通道。

结果很明显,造成死锁,证明两个单向通道之间是有通信的,有阻塞的。

最后通过源码,还是找到了答案:

由此,为避免接收到不需要的无效 零值 ,应修改接收 Goroutine -- receive 的写法:

go func() {
		defer wg.Done()
		for i := 0; i < 6; i++ { // 注意这里是 6
			x, ok := <-recv
			if ok {
				fmt.Print("receive\n")
				fmt.Println(x)
			}else{
				break
			}
		}
	}()

到此这篇关于Golang实现Directional Channel(定向通道)的文章就介绍到这了,更多相关Golang定向通道内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Golang通道的无阻塞读写的方法示例

    无论是无缓冲通道,还是有缓冲通道,都存在阻塞的情况,但其实有些情况,我们并不想读数据或者写数据阻塞在那里,有1个唯一的解决办法,那就是使用select结构. 这篇文章会介绍,哪些情况会存在阻塞,以及如何使用select解决阻塞. 阻塞场景 阻塞场景共4个,有缓存和无缓冲各2个. 无缓冲通道的特点是,发送的数据需要被读取后,发送才会完成,它阻塞场景: 通道中无数据,但执行读通道. 通道中无数据,向通道写数据,但无协程读取. // 场景1 func ReadNoDataFromNoBufCh() {

  • Golang实现Directional Channel(定向通道)

    通道可以是定向的( directional ).在默认情况下,通道将以双向的( bidirectional )形式运作,用户既可以把值放人通道,也可以从通道取出值;但是,通道也可以被限制为只能执行发送操作( send-only )或者只能执行接收操作( receive-only ). 通常可以叫 定向通道 ,也有人叫 单向通道 ,两者其实都是指向这篇短文要讨论的 Directional Channel . 下面直接举例子说明: package onlyChannelTest import ( "

  • golang开发中channel使用

    channel[通道]是golang的一种重要特性,正是因为channel的存在才使得golang不同于其它语言.channel使得并发编程变得简单容易有趣. channel的概念和语法 一个channel可以理解为一个先进先出的消息队列.channel用来在协程[goroutine]之前传递数据,准确的说,是用来传递数据的所有权.一个设计良好的程序应该确保同一时刻channel里面的数据只会被同一个协程拥有,这样就可以避免并发带来的数据不安全问题[data races]. 正文 channel

  • golang判断chan channel是否关闭的方法

    本文实例讲述了golang判断chan channel是否关闭的方法.分享给大家供大家参考,具体如下: 群里有朋友问,怎么判断chan是否关闭,因为close的channel不会阻塞,并返回类型的nil值,会导致死循环.在这里写个例子记录一下,并且分享给大家 如果不判断chan是否关闭 Notice: 以下代码会产生死循环 复制代码 代码如下: package main import (     "fmt" ) func main() {     c := make(chan int,

  • golang实现基于channel的通用连接池详解

    前言 golang的channel除了goroutine通信之外还有很多其他的功能,本文将实现一种基于channel的通用连接池.下面话不多说了,来一起看看详细的介绍吧. 功能 * 连接池中连接类型为interface{},使得更加通用 * 链接的最大空闲时间,超时的链接将关闭丢弃,可避免空闲时链接自动失效问题 * 使用channel处理池中的链接,高效 何为通用? 连接池的实现不依赖具体的实例,而依赖某个接口,本文的连接池选用的是io.Closer接口,只要是实现了该接口的对象都可以被池管理.

  • 详解java NIO之Channel(通道)

    通道(Channel)是java.nio的第二个主要创新.它们既不是一个扩展也不是一项增强,而是全新.极好的Java I/O示例,提供与I/O服务的直接连接.Channel用于在字节缓冲区和位于通道另一侧的实体(通常是一个文件或套接字)之间有效地传输数据. channel介绍 通道是访问I/O服务的导管.I/O可以分为广义的两大类别:File I/O和Stream I/O.那么相应地有两种类型的通道也就不足为怪了,它们是文件(file)通道和套接字(socket)通道.我们看到在api里有一个F

  • Golang优雅关闭channel的方法示例

    前言 最近使用go开发后端服务,服务关闭需要保证channel中的数据都被读取完,理由很简单,在收到系统的中断信号后,系统需要做收尾工作,保证channel的数据都要被处理掉,然后才可以关闭系统.但实现起来没那么简单,下面来一起看看详细的介绍吧. 关于Go channel设计和规范的批评: 在不能更改channel状态的情况下,没有简单普遍的方式来检查channel是否已经关闭了 关闭已经关闭的channel会导致panic,所以在closer(关闭者)不知道channel是否已经关闭的情况下去

  • golang中单向channel的语法介绍

    本文主要给大家介绍的是关于golang单向channel语法的相关内容,分享出来供大家参考学习,下面话不多说,来一起看看详细的介绍: 今天闲来无事补充一下golang的语法知识,想起来看看context的用法,结果碰到了一个没见过的channel语法: // A Context carries a deadline, cancelation signal, and request-scoped values // across API boundaries. Its methods are sa

  • Golang通道channel的源码分析

    目录 前言 channel基础结构 channel初始化 channel发送 channel接收 小结 前言 channel是golang中标志性的概念之一,很好很强大! channel(通道),顾名思义,是一种通道,一种用于并发环境中数据传递的通道.通常结合golang中另一重要概念goroutine(go协程)使用,使得在golang中的并发编程变得清晰简洁同时又高效强大. 今天尝试着读读golang对channel的实现源码,本文主要是自己个人对于Channel源码的学习笔记,需要的朋友可

  • Golang 探索对Goroutine的控制方法(详解)

    前言 在golang中,只需要在函数调用前加上关键字go即可创建一个并发任务单元,而这个新建的任务会被放入队列中,等待调度器安排.相比系统的MB级别线程栈,goroutine的自定义栈只有2KB,这使得我们能够轻易创建上万个并发任务,如此对性能提升不少.但随之而来的有以下几个问题: 如何等待所有goroutine的退出 如何限制创建goroutine的数量(信号量实现) 怎么让goroutine主动退出 探索--如何从外部杀死goroutine 本文记录了笔者就以上几个问题进行探究的过程,文中给

  • 基于Golang实现延迟队列(DelayQueue)

    目录 背景 原理 堆 随机删除 重置元素到期时间 Golang实现 数据结构 实现原理 添加元素 阻塞获取元素 Channel方式阻塞读取 性能测试 总结 背景 延迟队列是一种特殊的队列,元素入队时需要指定到期时间(或延迟时间),从队头出队的元素必须是已经到期的,而且最先到期的元素最先出队,也就是队列里面的元素是按照到期时间排序的,添加元素和从队头出队的时间复杂度是O(log(n)). 由于以上性质,延迟队列一般可以用于以下场景(定时任务.延迟任务): 缓存:用户淘汰过期元素 通知:在指定时间通

随机推荐