Go:channel
一、channel
基本使用
package main import (
"fmt"
) func main() {
// 使用 make 创建 channel
// 方式1
var intChan chan int
intChan = make(chan int, 3)
// 方式2
// intChan := make(chan int, 3) fmt.Printf("aChan的值:%v\n", intChan) // 0xc000086000
fmt.Printf("aChan本身的地址:%p\n", &intChan) // 0xc000080018 // 向管道发送值(注意给channel放入数据时,不能超过其容量)
intChan <- 10
intChan <- 20
fmt.Printf("aChan的len:%v\n", len(intChan)) //
fmt.Printf("aChan的cap:%v\n", cap(intChan)) // // 从管道中读取数据
int1 := <- intChan
int2 := <- intChan
fmt.Println(int1, int2) // 10 20
}
示例1
package main import (
"fmt"
) type Cat struct {
Name string
Age int
} func main() {
// 定义一个存放任意数据类型的管道3个数据
allChan := make(chan interface{}, 3)
allChan <- 10
allChan <- "pd"
cat := Cat{"tom", 10}
allChan <- cat
// 如果希望获得到管道中的第三个元素,则需先将前2个推出
<- allChan
<- allChan
newCat := <- allChan
fmt.Printf("newCat=%T , newCat=%v\n", newCat, newCat)
// fmt.Println(newCat.Name) // 编译不通过,错误
fmt.Println(newCat.(Cat).Name) // 使用类型断言,正确
}
示例2
channel 使用注意事项:
- channel中只能存放指定的数据类型;
- channel的数据放满后,就不能在放入了;
- 如果从 channel 取出数据后,就可以继续放入了;
- 在没有使用 goroutine 的情况下,如果 channel 数据被取完了,再取,就会报 dead lock。
二、关闭 channel
func main() {
intChan := make(chan int, 3)
intChan <- 10
intChan <- 20
// 关闭 channel
close(intChan)
// 关闭 channel 后,无法将数据写入到 channel 中,读取数据是可以的
num := <- intChan
fmt.Println(num) // 10
}
三、遍历 channel
channel 支持 for-range 的方式进行遍历:
- 在遍历时,如果 channel 没有关闭,则会出现 deadlock 错误;
- 在遍历时,如果 channel 已经关闭,则会正常遍历数据,遍历完后,就会退出遍历。
package main
import "fmt"
func main() {
ch := make(chan int, 3)
ch <- 10
ch <- 20
ch <- 30
// 关闭 channel
close(ch)
// 遍历 channel
for v := range ch {
fmt.Println(v)
}
}
四、应用实例
实例1:
- 开启一个 writeData 协程,向管道中写入30个整数;
- 开启一个 readData 协程,从管道中读取writeData写入的数据;
- writeData 和 readData 操作的是同一个管道;
- 主线程需要等待这两个协程都完成工作才能退出。
package main import "fmt" // 将数据放入管道
func writeData(intChan chan int) {
for i := 1; i <= 30; i++ {
// 放入数据
intChan<- i
fmt.Printf("写入数据:%v\n", i)
}
close(intChan) // 关闭管道
} // 从管道中获取数据
func readData(intChan chan int, exitFlagChan chan bool) {
for {
v, ok := <-intChan
if !ok {
break
}
fmt.Printf("获取数据:%v\n", v)
}
// 读取完数据后,写入一个"标志"到另一个管道
exitFlagChan<- true
close(exitFlagChan) // 关闭管道
} func main() {
intChan := make(chan int, 10)
exitFlagChan := make(chan bool, 1)
go writeData(intChan)
go readData(intChan, exitFlagChan)
// 获取"标志",用于结束主线程
for {
_, ok := <-exitFlagChan
if !ok {
break
}
}
}
阻塞:

对于示例1中,如果注销掉上图中的这行代码(即相当于只是向管道写入数据,而没有获取数据)。就会出现阻塞而发生 deadlock,原因是 intChan 的容量是10,而写入数据确是 50 个。
如果,编译器运行时发现一个管道只有写,没有读,则该管道会阻塞。PS:写管道和读管道的速度(频率)不一致,是没有关系的。
实例2:
需求:统计 1-5000 的数字中,那些是素数?
分析:
- 传统的方式:使用一个循环,判断各个数是不是素数;
- 协程的方式:将统计的素数的任务分配给(4个)goroutine 去完成(完成任务时间短)。
package main import "fmt" // 向intChan放入1-5000个整数
func putNum(intChan chan int) {
for i := 1; i <= 5000; i++ {
intChan<- i
}
close(intChan)
} // 从intChan取出数据,并判断是否为素数,如果是,就放入到resultChan中
func getNum(intChan chan int, resultChan chan int, exitChan chan bool) {
var flag bool
for {
num, ok := <-intChan
if !ok {
// intChan 取不到
break
}
// flag默认为true(假设取到的是素数)
flag = true
// 判断num是不是素数
for i := 2; i < num; i++ {
if num % i == 0 { // 说明该num不是素数
flag = false
break
}
}
if flag {
// 将这个数就放入到resultChan
resultChan<- num
}
}
// 还不能关闭 resultChan,因为是4个协程在工作
// 向 exitChan 写入true
exitChan<- true
} func main() {
// 保存原始数据的管道
intChan := make(chan int , 500)
// 保存结果的管道
resultChan := make(chan int, 1000)
// 标识退出的管道
exitChan := make(chan bool, 4) // 4个
// 产生数据
go putNum(intChan)
// 开启4个协程,从intChan取出数据,并判断是否为素数,如果是,就放入到resultChan
for i := 0; i < 4; i++ {
go getNum(intChan, resultChan, exitChan)
}
// 主线程进行处理,当从resultChan取出了4个结果,就可以放心的关闭resultChan
go func(){
for i := 0; i < 4; i++ {
<-exitChan
}
close(resultChan)
}()
// 遍历resultChan,把结果取出
count := 0
for {
r, ok := <-resultChan
if !ok{
break
}
count += 1
fmt.Printf("素数:%d\n", r)
}
fmt.Printf("素数数量:%d\n", count)
fmt.Println("主线程退出")
}
Go:channel的更多相关文章
- Go基础系列:channel入门
Go channel系列: channel入门 为select设置超时时间 nil channel用法示例 双层channel用法示例 指定goroutine的执行顺序 channel基础 chann ...
- Java NIO学习系列二:Channel
上文总结了Java NIO中的Buffer相关知识点,本文中我们来总结一下它的好兄弟:Channel.上文有说到,Java NIO中的Buffer一般和Channel配对使用,NIO中的所有IO都起始 ...
- handy源码阅读(四):Channel类
通道,封装了可以进行epoll的一个fd. struct Channel: private noncopyable { Channel(EventBase* base, int fd, int eve ...
- Netty入门(二):Channel
前言 Netty系列索引: 1.Netty入门(一):ByteBuf 2.Netty入门(二):Channel 在Netty框架中,Channel是其中之一的核心概念,是Netty网络通信的主体,由它 ...
- go:channel(未完)
注:1)以下的所有讨论建立在包含整形元素的通道类型之上,即 chan int 2)对于“<-”我的理解是,它可能是一个操作符(接收操作符),也 可能是类型的一部分(如“chan<- in ...
- GO语言练习:channel 缓冲机制
1.代码 2.运行 3.解析 1.代码 buffer.go package main import ( "fmt" "time" ) func readThre ...
- 专题:Channel Bonding/bonding
EtherChannel最初是由cisco提出,通过聚合多条物理链路为单条逻辑链路,从而实现高可用及提高吞吐量等目的.AgP(Port Aggregation Protocol,Cisco专有协议). ...
- (转)[疯狂Java]NIO:Channel的map映射
原文出自:http://blog.csdn.net/lirx_tech/article/details/51396268 1. 通道映射技术: 1) 其实就是一种快速读写技术,它将通道所连接的数据节点 ...
- Java-NIO(六):Channel聚集(gather)写入与分散(scatter)读取
Channel聚集(gather)写入: 聚集写入( Gathering Writes)是指将多个 Buffer 中的数据“聚集”到 Channel. 特别注意:按照缓冲区的顺序,写入 positio ...
随机推荐
- 天空盒的制作方法 Max来生成天空盒的六张图片
在虚拟现实技术中,需要产品展示,场景漫游等,只要想在内部有一个虚拟的3D天空,那么都要用到天空球:天空球目前基本做法主要有两种:分别是正方形的和球形的. 目前360度全景图主要用的是球形的,针对目前已 ...
- 简述网站、B/S架构与C/S架构
一.什么是网站? 定义:网站是指在因特网上根据一定的规则,使用HTML等工具制作的用于展示特定内容相关网页的集合. 简单地说,网站是一种沟通工具(或者说是一种软件——建设网站也是软件开发的一种),我们 ...
- [BZOJ4064/Cerc2012]The Dragon and the knights
Description 与当地鞋匠协会发生冲突的瓦维尔城堡的龙决定将它的狩猎场移出克拉科夫以减少敌对的邻居数量.现在他正在给和平而宁静的Bytes王国带来灾难与恐怖. 在Bytes王国有n条河流,每一 ...
- UvaLive6439(string使用、回文串)
样例手写一写很容易发现规律(前后一样的串,则ans+=2),实现起来却忘了string的便捷性,其实根本用不到哈希. ; int n, ans; string s, t1, t2; int main( ...
- Hibernate通过实体对象对应数据库表信息
Hibernate通过实体对象对应数据库表信息,包括:数据库表名称.主键列名.非主键列名等. 获取对象映射缓存管理类: AbstractEntityPersister aep = (AbstractE ...
- [已读]跨终端web
13年去听阿里技术嘉年华,鬼道分享了<移动优先前端产品的探索>.今年我买这本书,事实上是被高大上的目录吸引→ → 买来后发现,嘿,似曾相识啊,但还是老老实实得花一下午把书翻了一遍.翻完之后 ...
- Spark MLlib编程API入门系列之特征选择之向量选择(VectorSlicer)
不多说,直接上干货! 特征选择里,常见的有:VectorSlicer(向量选择) RFormula(R模型公式) ChiSqSelector(卡方特征选择). VectorSlicer用于从原来的特征 ...
- angularjs之ng-mode获取lobject类型里的键值
有时候数据库定义的时候,用一个对象来代表某个属性,之后直接访问对象就可以获取全部该对象的属性,但是有时需求访问对象中包含中的键值,引用键值的时候可以直接用.来获取对象的键值,比如 对象points: ...
- apt-get的一些坑
apt-get update:更新安装列表apt-get upgrade:升级软件apt-get install software_name :安装软件apt-get --purge remove ...
- LN : leetcode 684 Redundant Connection
lc 684 Redundant Connection 684 Redundant Connection In this problem, a tree is an undirected graph ...