go语言之并发编程 channel(1)
单向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)的更多相关文章
- go语言之并发编程 channel
前面介绍了goroutine的用法,如果有多个goroutine的话相互之间是如何传递数据和通信的呢.在C语言或者JAVA中,传输的方法包括共享内存,管道,信号.而在Go语言中,有了更方便的方法,就是 ...
- Go语言 7 并发编程
文章由作者马志国在博客园的原创,若转载请于明显处标记出处:http://www.cnblogs.com/mazg/ Go学习群:415660935 今天我们学习Go语言编程的第七章,并发编程.语言级别 ...
- 十.Go并发编程--channel使用
一.设计原理 Go 语言中最常见的.也是经常被人提及的设计模式就是: "不要通过共享内存来通信,我们应该使用通信来共享内存" 通过共享内存来通信是直接读取内存的数据,而通过通信来共 ...
- Go语言之并发编程(二)
通道(channel) 单纯地将函数并发执行是没有意义的.函数与函数间需要交换数据才能体现并发执行函数的意义.虽然可以使用共享内存进行数据交换,但是共享内存在不同的goroutine中容易发生竞态问题 ...
- Go语言之并发编程(一)
轻量级线程(goroutine) 在编写socket网络程序时,需要提前准备一个线程池为每一个socket的收发包分配一个线程.开发人员需要在线程数量和CPU数量间建立一个对应关系,以保证每个任务能及 ...
- Go语言之并发编程(四)
同步 Go 程序可以使用通道进行多个 goroutine 间的数据交换,但这仅仅是数据同步中的一种方法.通道内部的实现依然使用了各种锁,因此优雅代码的代价是性能.在某些轻量级的场合,原子访问(atom ...
- Go语言之并发编程(三)
Telnet回音服务器 Telnet协议是TCP/IP协议族中的一种.它允许用户(Telnet客户端)通过一个协商过程与一个远程设备进行通信.本例将使用一部分Telnet协议与服务器进行通信. 服务器 ...
- go语言之并发编程同步一
前面介绍了采用go语法的并行操作以及channel.既然是并行操作,那么就涉及到数据原子性以及同步的问题.所以在Go里面也需要采用同步的机制. 互斥锁: 由标准库代码包sync中的Mutex结构体类型 ...
- go语言入门(10)并发编程
1,概述 1.1并发和并行 并行(parallel):指在同一时刻,有多条指令在多个处理器上同时执行. 并发(concurrency):指在同一时刻只能有一条指令执行,但多个进程指令被快速的轮换执行, ...
随机推荐
- Shader toy (顺手写两个Gyro)(纯代码写3D)
Shader toy (A new world) 1.一个多月了,突然忘记CSDN的password了.由于每次输password的时候都要计算一遍,于是没有计算出来- 2.回头发现都过了半年了,都快 ...
- Ubuntu16.04安装QQ
说明:一开始,我在Ubuntu 16.04下安装的QQ版本是Wineqq2013SP6-20140102-Longene,但后来发现这个版本QQ在linux下问题很多,比如不能用键盘输入密码,QQ表情 ...
- B树、B-树、B+树、B*树(转)
B树 即二叉搜索树: 1.所有非叶子结点至多拥有两个儿子(Left和Right): 2.所有结点存储一个关键字: 3.非叶子结点的左指针指向小于其关键字的子树,右指针指向大于其关键字的子树: 如: B ...
- Hbase笔记:批量导入
工作中可能会有对HBase的复杂操作,我们现在对HBase的操作太简单了.复杂操作一般用HBaseScan操作,还有用框架对HBase进行复杂操作,iparler,sharker.我们说HBase是数 ...
- 最常用的几个python库--学习引导
核心库 1.NumPy 当我们用python来处理科学计算任务时,不可避免的要用到来自SciPy Stack的帮助.SciPy Stack是一个专为python中科学计算而设计的软件包,注意不要将它 ...
- 非常easy学习的JQuery库 : (二) 选择器
作用 选择器同意您对元素组或单个元素进行操作. 在前面的章节中,我们介绍了一些有关怎样选取 HTML 元素的实例. 关键点是学习 jQuery 选择器是怎样准确地选取您希望应用效果的元素. jQuer ...
- reveal end of document
window - Preferences - Run/Debug - Console 将 Console buffer size (characters)设置大一点
- IE浏览器下,输入框最后不显示X
IE浏览器下,输入框最后不显示X.设置: .login-input::-ms-clear { display: none; } .login-input::-ms-reveal { display: ...
- 看完这篇还不会 GestureDetector 手势检测,我跪搓衣板!
引言 在 android 开发过程中,我们经常需要对一些手势,如:单击.双击.长按.滑动.缩放等,进行监测.这时也就引出了手势监测的概念,所谓的手势监测,说白了就是对于 GestureDetector ...
- Quartz.Net - Lesson2: 任务和触发器
Lesson 2: 任务和触发器 本系列文章是官方3.x文档的翻译,原文地址:https://www.quartz-scheduler.net/documentation/quartz-3.x/tut ...