单向channel:

单向通道可分为发送通道和接收通道。但是无论哪一种单向通道,都不应该出现在变量的声明中,假如初始化了这样一个变量

var uselessChan chan <- int =make(chan <- int,10)

这样一个变量该如何使用呢,这样一个只进不出的通道没有什么实际意义。那么这种单向通道的应用场景在什么地方呢。我们可以用这种变换来约束对通道的使用方式。比如下面的这种声明

func Notify(c chan <- os.Signal, sig… os.Signal)

该函数的第一个参数的类型是发送通道类型。从参数的声明来看,调用它的程序应该传入一个只能发送而不能接收的通道。但是实际上应该传入的双向通道,Go会依据该参数的声明,自动把它转换成一个单向通道。Notify函数中的代码只能向通道c发送数据,而不能从它那里接收数据,在该函数中从通道c接收数据会导致编译错误。但是在函数之外不存在这个约束。

现在对SignalNotifier接口的声明稍作改变,如下:

type SignalNotifier interface{

Notify(sig…os.Signal) <- chan os.Signal

}

现在这个声明放在了函数外面,这种实现方法说明Notify方法的调用只能从作为结果的通道中接收元素值,而不能向其发送元素值。来看一个单向通道的例子

var strChan=make(chan string,3)

var mapChan=make(chan map[string]int,1)

func receive(strChan <- chan string,syncChan1 <- chan struct{},syncChan2 chan <- struct{}){

<-syncChan1

fmt.Println("Received a sync signal and wait a second...[receiver]")

time.Sleep(time.Second)

for{

if elem,ok:=<-strChan;ok{

fmt.Println("Received:",elem,"[receiver]")

}else{

break

}

}

fmt.Println("stopped.[receiver]")

syncChan2 <- struct{}{}

}

func send(strChan chan <- string,syncChan1 chan <- struct{},syncChan2 chan <- struct{}){

for _,elem:=range[]string{"a","b","c","d","e"}{

strChan <- elem

fmt.Println("sent:",elem,"[sender]")

if elem == "c"{

syncChan1 <- struct{}{}

fmt.Println("sent a sync signal.[sender]")

}

}

fmt.Println("wait 2 seconds...[sender]")

time.Sleep(time.Second*2)

close(strChan)

syncChan2 <- struct{}{}

}

func main(){

syncChan1:=make(chan struct{},1)

syncChan2:=make(chan struct{},2)

go receive(strChan,syncChan1,syncChan2)

go send(strChan,syncChan1,syncChan2)

<-syncChan2

<-syncChan2

}

receive函数只能对strChan和syncChan1通道进行接收操作。而send函数只能对这2个通道进行发送操作。区别点在于chan 和 <-的位置。chan <- 表明是接收通道。<- chan表明是发送通道。运行结果如下:

sent: a [sender]

sent: b [sender]

sent: c [sender]

sent a sync signal.[sender]

Received a sync signal and wait a second...[receiver]

sent: d [sender]

Received: a [receiver]

Received: b [receiver]

Received: c [receiver]

Received: d [receiver]

Received: e [receiver]

sent: e [sender]

wait 2 seconds...[sender]

stopped.[receiver]

非缓冲channel

如果在初始化一个通道时将其容量设置为0或者直接忽略对容量的设置。就会使该通道变成一个非缓冲通道。和异步的方式不同,非缓冲通道只能同步的传递元素值

1 向此类通道发送元素值的操作会被阻塞。直到至少有一个针对通道的接收操作进行为止。该接收操作会首先得到元素的副本,然后再唤醒发送方所在的goroutine之后返回。也就是说,这是的接收操作会在对应的发送操作完成之前完成。

2 从此类通道接收元素值的操作会被阻塞,直到至少有一个针对该通道的发送操作进行为止。发送操作会直接把元素值赋值给接收方,然后再唤醒接收方所在的goroutine之后返回。这时的发送操作会在对应的接收操作之前完成。

func main(){

sendingInterval:=time.Second

receptionInterval:=time.Second*2

intChan:=make(chan int,0)

go func(){

var ts0,ts1 int64

for i:=1;i<=5;i++{

intChan <- i

ts1=time.Now().Unix()

if ts0 == 0{

fmt.Println("sent:",i)

}else{

fmt.Println("Sent:",i,"[interval:",ts1-ts0,"]\n")

}

ts0=time.Now().Unix()

time.Sleep(sendingInterval)

}

close(intChan)

}()

var ts0,ts1 int64

Loop:

for{

select{

case v,ok:=<-intChan:

if !ok{

break Loop

}

ts1=time.Now().Unix()

if ts0 == 0{

fmt.Println("receive:",v)

}else{

fmt.Println("receive:",v,"[interval:",ts1-ts0,"]\n")

}

}

ts0=time.Now().Unix()

time.Sleep(receptionInterval)

}

fmt.Println("End.")

}

运行结果:

sent: 1

receive: 1

receive: 2 [interval: 2 ]

Sent: 2 [interval: 2 ]

Sent: 3 [interval: 2 ]

receive: 3 [interval: 2 ]

receive: 4 [interval: 2 ]

Sent: 4 [interval: 2 ]

receive: 5 [interval: 2 ]

Sent: 5 [interval: 2 ]

End.

可以看到发送操作和接收操作都与receptioninterval的间隔一致。如果把sendingInterval改成time.Second*4. 则结果如下:发送操作和接收操作都与sendingInterval的间隔一致

sent: 1

receive: 1

Sent: 2 [interval: 4 ]

receive: 2 [interval: 4 ]

Sent: 3 [interval: 4 ]

receive: 3 [interval: 4 ]

Sent: 4 [interval: 4 ]

receive: 4 [interval: 4 ]

Sent: 5 [interval: 4 ]

receive: 5 [interval: 4 ]

End.

go语言之并发编程 channel(1)的更多相关文章

  1. go语言之并发编程 channel

    前面介绍了goroutine的用法,如果有多个goroutine的话相互之间是如何传递数据和通信的呢.在C语言或者JAVA中,传输的方法包括共享内存,管道,信号.而在Go语言中,有了更方便的方法,就是 ...

  2. Go语言 7 并发编程

    文章由作者马志国在博客园的原创,若转载请于明显处标记出处:http://www.cnblogs.com/mazg/ Go学习群:415660935 今天我们学习Go语言编程的第七章,并发编程.语言级别 ...

  3. 十.Go并发编程--channel使用

    一.设计原理 Go 语言中最常见的.也是经常被人提及的设计模式就是: "不要通过共享内存来通信,我们应该使用通信来共享内存" 通过共享内存来通信是直接读取内存的数据,而通过通信来共 ...

  4. Go语言之并发编程(二)

    通道(channel) 单纯地将函数并发执行是没有意义的.函数与函数间需要交换数据才能体现并发执行函数的意义.虽然可以使用共享内存进行数据交换,但是共享内存在不同的goroutine中容易发生竞态问题 ...

  5. Go语言之并发编程(一)

    轻量级线程(goroutine) 在编写socket网络程序时,需要提前准备一个线程池为每一个socket的收发包分配一个线程.开发人员需要在线程数量和CPU数量间建立一个对应关系,以保证每个任务能及 ...

  6. Go语言之并发编程(四)

    同步 Go 程序可以使用通道进行多个 goroutine 间的数据交换,但这仅仅是数据同步中的一种方法.通道内部的实现依然使用了各种锁,因此优雅代码的代价是性能.在某些轻量级的场合,原子访问(atom ...

  7. Go语言之并发编程(三)

    Telnet回音服务器 Telnet协议是TCP/IP协议族中的一种.它允许用户(Telnet客户端)通过一个协商过程与一个远程设备进行通信.本例将使用一部分Telnet协议与服务器进行通信. 服务器 ...

  8. go语言之并发编程同步一

    前面介绍了采用go语法的并行操作以及channel.既然是并行操作,那么就涉及到数据原子性以及同步的问题.所以在Go里面也需要采用同步的机制. 互斥锁: 由标准库代码包sync中的Mutex结构体类型 ...

  9. go语言入门(10)并发编程

    1,概述 1.1并发和并行 并行(parallel):指在同一时刻,有多条指令在多个处理器上同时执行. 并发(concurrency):指在同一时刻只能有一条指令执行,但多个进程指令被快速的轮换执行, ...

随机推荐

  1. DataSet之增删改查操作(DataGridView绑定)

    DataSet数据集,数据缓存在客户端内存中,支持断开式连接.DataGridView控件绑定DataSet时,它自动的改变的DS的行的状态,而且在做增删改查的时候,可以借助SqlCommandBui ...

  2. Node.js 使用angularjs取得Nodejs http服务端返回的JSON数组示例

    server.js代码: // 内置http模块,提供了http服务器和客户端功能(path模块也是内置模块,而mime是附加模块) var http=require("http" ...

  3. JAVA Eclipse中的Android程序如何使用线程

    我们先单独定义一个java类,名字可以任意取(比如叫做ClientHeartBeat类,我当前在做一个socket通信的客户端,我们假定需要一个可以测试心跳的程序),注意他要继承Thread,然后重载 ...

  4. WAMP集成开发环境

    集成开发环境WampServer能够摆脱环境配置的烦恼,对初学者来说,能够快速编写代码,现把安装过程介绍一下. W:Windows A:Apache M:MySql P:PHP 是一套整合在一起的PH ...

  5. Hdu 2243 考研路茫茫——单词情结 (AC自己主动机+矩阵)

    哎哟喂.中文题. . .不说题意了. 首先做过POJ 2778能够知道AC自己主动机是能够求出长度为L的串中不含病毒串的数量的. POJ 2778的大概思路就是先用全部给的病毒串建一个AC自己主动机. ...

  6. 设计模式之十八:桥接模式(Bridge)

    桥接模式: 将抽象部分和它的实现部分相分离开来,以使它们能够单独地变化. UML图: 主要包含: Abstraction:定义了抽象部分的接口.操作一个实现部分对象的引用. RefinedAbstra ...

  7. BZOJ 1012 线段树||单调队列

    非常裸的线段树  || 单调队列: 假设一个节点在队列中既没有时间优势(早点入队)也没有值优势(值更大),那么显然不管在如何的情况下都不会被选为最大值. 既然它仅仅在末尾选.那么自然能够满足以上的条件 ...

  8. Dephi泛型

    TArray TEnumerator(抽象) TEnumerable(抽象) 实际使用:TList TQueue TStack TPair TDictionary ,内部都包含 TValueEnume ...

  9. asp.net core mvc视频A:笔记3-2.表单使用

    页面上呈现表单的两种方式 新建项目,增加Test控制器,增加Index视图 方式一:HTML构建表单 运行 方式二:HTML 运行 数据绑定 处理方法 调用结果 登录后返回值 默认值绑定 方式一: 控 ...

  10. nightwatch API

    API Nightwatch的API分为四个部分 1.Expect 在browser实例上以.expect.element开头的BDD(行为驱动测试)风格的接口,0.7及以上版本nightwatch可 ...