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 的基本使用方法的更多相关文章

  1. golang channel的使用以及调度原理

    golang channel的使用以及调度原理 为了并发的goroutines之间的通讯,golang使用了管道channel. 可以通过一个goroutines向channel发送数据,然后从另一个 ...

  2. golang编译源代码和交叉编译方法

    目录 golang编译源代码和交叉编译方法 编译源代码 编译go1.4 编译go1.12 交叉编译 golang编译源代码和交叉编译方法 编译源代码 golang编译其实很简单,下载一份最新的源代码后 ...

  3. golang channel关闭后,是否可以读取剩余的数据

    golang channel关闭后,其中剩余的数据,是可以继续读取的. 请看下面的测试例子. 创建一个带有缓冲的channel,向channel中发送数据,然后关闭channel,最后,从channe ...

  4. golang init方法和main方法初始化顺序

    init()和main()方法是golang默认的两个方法,不需要我们调用,程序执行会自动寻找项目中的这俩方法.现在我们就讲一种通用的情况:main 包下 导入了 init2 包而在init2 包下又 ...

  5. golang channel原理

    channel介绍 channel一个类型管道,通过它可以在goroutine之间发送和接收消息.它是Golang在语言层面提供的goroutine间的通信方式. 众所周知,Go依赖于称为CSP(Co ...

  6. golang channel 用法转的

    一.Golang并发基础理论 Golang在并发设计方面参考了C.A.R Hoare的CSP,即Communicating Sequential Processes并发模型理论.但就像John Gra ...

  7. golang channel初次接触

    goroutine之间的同步 goroutine是golang中在语言级别实现的轻量级线程,仅仅利用go就能立刻起一个新线程.多线程会引入线程之间的同步问题,经典的同步问题如生产者-消费者问题,在c, ...

  8. 如何优雅的关闭Golang Channel?

    Channel关闭原则 不要在消费端关闭channel,不要在有多个并行的生产者时对channel执行关闭操作. 也就是说应该只在[唯一的或者最后唯一剩下]的生产者协程中关闭channel,来通知消费 ...

  9. golang channel 源码剖析

    channel 在 golang 中是一个非常重要的特性,它为我们提供了一个并发模型.对比锁,通过 chan 在多个 goroutine 之间完成数据交互,可以让代码更简洁.更容易实现.更不容易出错. ...

随机推荐

  1. JTSL/EL Expression学习

    最早的一个学习笔记,时间过去了久了,供java web初学者参考. JTSL/EL Expression学习安排 学习目标:掌握几个常见标签的使用,通晓工作原理,详细到代码层面,遇到问题时能查得出异常 ...

  2. Banner中文字怎么排版才好看?

    今天这命题,相信有很多人提出过疑问,一个好的文字排版会给你的作品增添色彩,我们先看看好的作品是怎样的. 看完这些图大家都能感觉出来这是一个好的作品,大家天生就对美和丑有一定的区分. 其实文字排版也好, ...

  3. csv中文乱码

    处理办法:https://jingyan.baidu.com/album/3c48dd3464b46ce10be3581f.html?picindex=2

  4. How to Set Up an Rsync Daemon on Your Linux Server

    Introduction This tutorial will take you through setting up an rsync daemon on your Linux server. Yo ...

  5. 解决 Ubuntu 下 sudo 命令执行速度慢的问题

    1.首先如果当用登录的用户名不在"/etc/sudoers"文件中,是不能执行sudo命令的.可以用root身份手动修该文件,把当前登录用户名加入该文件中. 2.用"ho ...

  6. 关于apicloud图片缓存

    imageCache如果是同一个地址,得到的缓存文件名字是一样的.可能是对url md5了一下. apicloud目前有两种清除方式1 一种是api.clearCache   另一种方法当然是强大的 ...

  7. 2018.09.07 loj#10166 数字游戏(数位dp)

    传送门 数位dp板子题. f[i][mod]" role="presentation" style="position: relative;"> ...

  8. 2018.08.06 bzoj1503: [NOI2004]郁闷的出纳员(非旋treap)

    传送门 平衡树简单题. 直接用fhgtreap实现分裂和合并就没了. 代码: #include<bits/stdc++.h> #define N 100005 using namespac ...

  9. 将IP地址转化为整数

    $ip = 'IP地址';echo $intip = sprintf('%u',ip2long($ip)); //转换为无符号整型echo long2ip($intip);//将整型转换为ip

  10. IntelliJ IDEA 2017版 加载springloaded-1.2.4.RELEASE.jar实现热部署

    1.配置pom.xml文档(详见:http://www.cnblogs.com/liuyangfirst/p/8318664.html) <?xml version="1.0" ...