Golang channel 的基本使用方法
package main import (
"fmt"
"learner/Add"
"time"
) //a. 普通类型,普通变量保存的就是值,也叫值类型
//b. 获取普通变量的内存地址,用&,比如: var a int, 获取a的内存地址:&a
//c. 指针类型,指针变量存的就是一个内存地址,这个地址指向值
//d. 获取指针类型所指向的值,使用:*,比如:var *p int, 使用*p获取p指向的值
//e. 将一个内存地址给一个指针类型进行赋值(不可以直接将变量赋值给指针,需要将内存地址赋值给指针): var a int=5, var p *int = &a // 在工程上有两种最常见的并发通信模型: 共享数据和消息通信, go语言选择后者,通过通信进行共享内存
// channel, goroutine 间的通信方式, 进程内的的通信.进程间的通信建议使用socket或者http等通信协议.
// channel 是类型相关的, 一个channel只能传递一种指定类型的值, 这个值需要在声明channel时指定(可以理解为指定元素类型的管道) // 超时控制的经典实现
func chan_time_out_handler(ch chan int) (item bool){
// 使用 select 为channel实现超时机制, select的一个case必须是一个面向channel的操作
// 定义一个time_out chan
timeOut := make(chan bool, 1)
go func(){
time.Sleep(1e9) // 等待一秒钟
timeOut<- true
}()
// 利用time_out这个chan实现超时之后做何操作
select {
case a := <- ch: // 尝试从ch这个chan中读取数据
fmt.Println(a)
return true
case <- timeOut: // 在等待时间范围内一直没有从ch中读取到了数据但是从time_out 这个 chan 中读取到了数据
return false
}
} // 只往chan中写入数据
func chan_in(ch_in chan<- int) {
for i:=0; i <= 10; i++{
ch_in <- 1
}
// 如果是使用range遍历chan, 那么当chan关闭时, 读取操作会立即结束,跳出循环(注意,这是channel中可能仍会存在数据),
// channel关闭后,其实仍然可以从中读取已发送的数据(使用range无法实现, 可以使用常规的循环读取channel的方式),读取完数据后,将读取到零值,可以多次读取(仍然是零值)
close(ch_in) // 当多个goroutine都使用了同一个channel时, 任何一个goroutine 中关闭了这个了这个channel, 其他goroutine将无法继续对这个channel进行读取
} // 只从chan读出数据
func chan_out(ch_out <-chan int) {
// 使用range, 当这个channel关闭时,就会跳出循环,但是channel里面仍然可能存在数据
// x, ok := <- ch_out, 如果ok返回的是false,那么就表示这个chan已经关闭
for value := range ch_out{
fmt.Printf("+++++++++++++++++%d", value)
}
} func main() { // 切片和map 都是指针类型的数据, 指针类型的数据都可以使用make()进行分配内存
chs := make([]chan int, 10) // 定义一个切片并分配内存, 元素是chan类型, 这个chan内可以保存的元素为int类型, 该切片初始内存可以保存10个元素(不是channel的缓冲区, 是切片的初始大小)
for i := 0; i < 10; i++ {
chs[i] = make(chan int, 3) // 定义一个chan并分配内存, 缓冲区大小为3, 然后保存到切片中, 如果不设置缓冲区,当写入一个元素时,如果这个元素不被读取掉,写操作将会被阻塞
go Add.TestAddTwo(chs[i]) // 开启协程发送chan
} for _, ch := range (chs) {
fmt.Println("====================", len(ch)) //当程序运行到这里时, 这个channel有可能并没有写入数据,所以长度有可能为0 1 2
a := <-ch // 当这里从当前channel读取不到数据时就会阻塞
// b := <-ch // 继续读取, 读取不到就堵塞
fmt.Println(a) item := chan_time_out_handler(ch)
fmt.Println(item) // 当channel写完数据操作完成后如果没有关闭,读取完数据,chan为空时,将会阻塞, 从而有可能造成死锁, 所以chan使用完必须关闭 } // 单向channel的实现,当需要将一个单向的channel从读变为写,或者从写变为读时,需要进行类型转换
// 第一个步,定义一个正常的channel
ch_normal := make(chan int)
// 第二步进行类型转换,将ch_normal 转换为只允许写的channel
var ch_in chan<- int = ch_normal
go chan_in(ch_in)
// 第三步 生成一个只允许进行读的channel
var ch_out <-chan int = ch_normal
chan_out(ch_out)
} // 当向一个channel写入数据, 在这个channel被读取前, 这个操作是阻塞的(在缓冲区写满之前, 即使没有读取操作,写操作都不会阻塞)
// 当从一个channel读取数据时,在对应的channel写入数据前, 这个操作也是阻塞的,从而可以利用channel实现了类似锁的功能, 进而保证
// 了所有goroutine完成后主函数才返回
// 缓冲区满之后将会阻塞,除非有goroutine对其进行操作, 否则协程就会停留在向该channel写入元素的步骤上, 直到主进程退出, 向channel写入数据的协程也就退出. 协程的阻塞不影响主进程的执行 // 定义一个channel var chanName chan ElementType
// 多层定义,例如定义一个 map, 键是string类型,元素是bool类型的channel: var myMap map[string] chan bool
// 声明以后,定义一个channel 并赋值给变量: map["firstChan"] := make(chan false) , 使用内建函数make() // 如果是使用range遍历chan, 那么当chan关闭时, 读取操作会立即结束,跳出循环(注意,这是channel中可能仍会存在数据)
// 当多个goroutine都使用了同一个channel时, 任何一个goroutine 中关闭了这个了这个channel,
// 其他goroutine将无法继续对这个channel进行读取, 可以在主进程中进行守护, 等所有的goroutine执行完毕后再去关闭channel
// close(chan) //关闭一个channel // 判断一个channel是否已关闭
//1. 如果channel已经关闭,继续往它发送数据会导致panic: send on closed channel
//2. 关闭一个已经关闭的channel也会导致panic: close of closed channel
func test2(ch chan int){
for{
if value,ok:=<-ch;ok{
//do somthing
fmt.Print(value)
}else{
break //ok 为false, 表示channel已经被关闭,退出循环
}
}
} // channel关闭后,仍然可以从中读取已发送的数据(使用range无法实现),读取完数据后,将读取到零值,可以多次读取。
func test1(){
ch:=make(chan int,3)
ch<-3
ch<-2
ch<-1
close(ch)
fmt.Print(<-ch)
fmt.Print(<-ch)
fmt.Print(<-ch)
fmt.Print(<-ch)
fmt.Print(<-ch)
}
Golang channel 的基本使用方法的更多相关文章
- golang channel的使用以及调度原理
golang channel的使用以及调度原理 为了并发的goroutines之间的通讯,golang使用了管道channel. 可以通过一个goroutines向channel发送数据,然后从另一个 ...
- golang编译源代码和交叉编译方法
目录 golang编译源代码和交叉编译方法 编译源代码 编译go1.4 编译go1.12 交叉编译 golang编译源代码和交叉编译方法 编译源代码 golang编译其实很简单,下载一份最新的源代码后 ...
- golang channel关闭后,是否可以读取剩余的数据
golang channel关闭后,其中剩余的数据,是可以继续读取的. 请看下面的测试例子. 创建一个带有缓冲的channel,向channel中发送数据,然后关闭channel,最后,从channe ...
- golang init方法和main方法初始化顺序
init()和main()方法是golang默认的两个方法,不需要我们调用,程序执行会自动寻找项目中的这俩方法.现在我们就讲一种通用的情况:main 包下 导入了 init2 包而在init2 包下又 ...
- golang channel原理
channel介绍 channel一个类型管道,通过它可以在goroutine之间发送和接收消息.它是Golang在语言层面提供的goroutine间的通信方式. 众所周知,Go依赖于称为CSP(Co ...
- golang channel 用法转的
一.Golang并发基础理论 Golang在并发设计方面参考了C.A.R Hoare的CSP,即Communicating Sequential Processes并发模型理论.但就像John Gra ...
- golang channel初次接触
goroutine之间的同步 goroutine是golang中在语言级别实现的轻量级线程,仅仅利用go就能立刻起一个新线程.多线程会引入线程之间的同步问题,经典的同步问题如生产者-消费者问题,在c, ...
- 如何优雅的关闭Golang Channel?
Channel关闭原则 不要在消费端关闭channel,不要在有多个并行的生产者时对channel执行关闭操作. 也就是说应该只在[唯一的或者最后唯一剩下]的生产者协程中关闭channel,来通知消费 ...
- golang channel 源码剖析
channel 在 golang 中是一个非常重要的特性,它为我们提供了一个并发模型.对比锁,通过 chan 在多个 goroutine 之间完成数据交互,可以让代码更简洁.更容易实现.更不容易出错. ...
随机推荐
- go实现的简易TCP的客户端和服务器
今天介绍golang版本的通信基础:基于TCP的客户端和服务器实现,参考书籍:The Way To Go 那时学习java的时候也是做过通信的,当时是socket编程,服务器监听某一个端口,然后客户机 ...
- 【文件下载】Java下载文件的几种方式
[文件下载]Java下载文件的几种方式 摘自:https://www.cnblogs.com/sunny3096/p/8204291.html 1.以流的方式下载. public HttpServl ...
- Python模拟登陆淘宝并统计淘宝消费情况的代码实例分享
Python模拟登陆淘宝并统计淘宝消费情况的代码实例分享 支付宝十年账单上的数字有点吓人,但它统计的项目太多,只是想看看到底单纯在淘宝上支出了多少,于是写了段脚本,统计任意时间段淘宝订单的消费情况,看 ...
- 2018.09.12 poj3621Sightseeing Cows(01分数规划+spfa判环)
传送门 01分数规划板题啊. 发现就是一个最优比率环. 这个直接二分+spfa判负环就行了. 代码: #include<iostream> #include<cstdio> # ...
- python面向对象开发的自我理解
详细代码理解可以参考 笨鸟教程博客:http://www.runoob.com/python3/python3-class.html 面向对象经常被提起,那到底什么是面向对象呢? 它的基本概念:类, ...
- 对于Serializable id类型的数据的测试
今天编写了一个这样的例子,然后进行了Junit测试,但是发现类型总是不匹配,最后测出如下 public <T> void deleteEntry(Class<T> t, Ser ...
- 日期 时间选择器(DatePicker和TimePicker)实现用户选择
日期和时间 作者的设计TimePicker时,大小分布不合理,我调整宽度为match-parent高度为wrap-parent就可以了. public class MainActivity exten ...
- wadl 的自动生成(cxf版本3.1.1)
官方文档 http://cxf.apache.org/docs/jaxrs-services-description.html 举例: package cn.zno; import javax.ws. ...
- nodejs中如何使用mysql数据库[node-mysql翻译]
nodejs中如何使用mysql数据库 db-mysql因为node-waf: not found已经不能使用,可以使用mysql代替. 本文主要是[node-mysql]: https://www. ...
- day15(mysql之零碎知识)
数据完整性 实体完整性 实体: 表中一行(一行记录)代替一个实体 实体完整性的作用: 标识每一行数据不重复. 约束类型: 主键约束, 唯一约束,自动增长列. 主键约束: 标识该列唯一,非空. 注: ...