golangChannel
[TOC]
channle 都是应用于两个go程,一个读,一个写
- channel 具有阻塞的作用,类似go程之间对同步资源进行锁机制
- 具有数据传递的功能
一、无缓冲channel —-(同步)
无缓冲channel 定义
var ch =make(chan string )或者ch :=make(chan string)
无缓冲channel的说明
- ch <- “hehe” 写数据,数据没有被在读,则为阻塞
- <-ch 读数据,数据没有没有在写, 则为阻塞
len(ch):channel中未读取的元素个数,cap(ch):channel中通道的容量 。 都是零
二、有缓冲channel ——(异步)
有缓冲channel定义
var ch =make(chan string ,3)或者ch :=make(chan string ,3)- 当存储的元素个数超过了
cap(ch)才会阻塞
三、关闭channel
close(ch),不再向对端发送数据判断chan是否关闭 ,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31if num,ok:=<-chan; ok ==true{
fmt.Println("已经关闭")
}
// 无缓冲 关闭channle,读端 ok为false,num为0
// 如果channel已经关闭 ,写端出现panic send on closed channel
// 如果channle有缓冲,当len(ch) 的值没有超过cap(ch),那么close(ch)是阻塞的
// 如果channle无缓冲,当ch中存在元素,close(ch)也是阻塞的
func main() {
ch:=make(chan int)
go func() {
for i:=0;i<=100;i++{
ch <-i
}
close(ch) //这里close其实是阻塞的
}()
go func() {
for{
if num,ok:=<-ch;ok{
fmt.Print(num)
close(ch)
}else{
fmt.Println("jieshu",num)
}
}
}()
四、单向channel
双向channel
ch:=make(chan string )单项写channel
var readCh chan<- int单向读channel
var writech <-chan
单向channel和双向channel转换
- 双向转单向
readch = ch - 单向不可以转双向
传参:传【引用】
Channel通信的时候,要保证channle不能在同一个go程之中
五、消费者,生产者模型
- 解耦(降低消费者和生产者直接的耦合度)
- 并发(消费者,生产者消费不对等,能保持正常的通信)
- 缓存(生产者和消费者处理不一致时,暂存数据)
生产者,消费者实现:
- 有缓冲的channel :异步同行
- 无缓冲的channel:同步通信
1 | package main |
六、定时器: 三种定义方法
time.sleep() ; time.NewTimer() ;time.After()
1 | package main |
七、select 语句
select (退出for 循环中的select ,用return 或者goto的方式)
1 | func main() { |
八、锁
golang死锁模型:
- 1、单go程自己死锁: channel至少在两个go程中使用,否则思索
- 2、go程间channel访问顺序:使用channle一端写(读),要保证另一一段读(写),同时有机会执行,否则思索
- 3、多go程,多channel交叉死锁
- 4、在go语言中,尽量不要将互斥锁和channel一起使用,会造成隐形死锁
golang 锁
- 1.channel 定义互斥锁
1 | //定义个全局channel |
2.用锁定义互斥锁(这种锁,我们一般称为:–>建议锁)
1
2
3
4
5
6var mutex sync.Mutex //定义锁
//对共享资源枷锁
mutex.Lock()
fmt.Pirnt('hello')
muter.Unlock()3.读写锁: 读时共享,写时独占(写比读优先级要高)
var rwmutex2 sync.RWMutex定了一把锁,这个锁带有读和写的属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43var rwmutex2 sync.RWMutex
var I int
func reader2(i int){
for{
// 读锁,并发共享
rwmutex2.RLock()
a:=I
rwmutex2.RUnlock()
fmt.Printf("=======第%d个读进程,读取到%d\n",i,a)
time.Sleep(time.Second)
}
}
func writer2(a int){
for{
num:=rand.Intn(100)
// 写锁,独占
rwmutex2.Lock()
I=num
fmt.Printf("第%dth写go程,写数据:%d \n" ,a,num)
time.Sleep(time.Second*2)
rwmutex2.Unlock()
}
}
func main(){
for i:=0;i<=3;i++{
go reader2(i)
}
for i:=0;i<=3;i++{
go writer2(i)
}
for{
;
}
}- channel 无法完成共享读,因此需要对读完成共享数据读的时候,使用读写锁
条件变量 type Cond struct{}
适用生产者消费者模型:本身不是锁,经常要与锁结合使用,他是一个结构体
作用:
- 加锁
- 访问公共区域(比如带缓冲channle)
- 解锁
- 唤醒阻塞在条件变量上对端
条件变量Cond常见方法:
wait()函数 使用场景- 阻塞等待条件变量满足
- 释放已掌握的互斥锁相当于 cond.L.Unlock() ;注意:两步分为原子操作 <—-及不可以分开
- 当被唤醒,Wati()函数返回时候,解决阻塞并重新获取互斥锁。相当于cond.L.Lock()
cond.Single()唤醒对端cond.Broadcast()惊群唤醒
创建条件变量流程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25//1.创建条件变量
var cond sync.Cond
//2.创建条件变量指定锁
cond.L=new(sync.Mutex)
//3. 给公共区加锁
cond.L.Lock()
//4.判断是否达到阻塞条件
//
//4.1 producer 端判断条件
for len(ch)==cap(ch){
cond.Wait() //1.阻塞2.解锁 3.加锁
}
//4.2 consumer端判断
for len(ch)==0{
cond.Wait()
}
//5.访问公共区,读写,打印
//6.对公共区条件变量解锁
cond.L.Unlock()
//7.唤醒阻塞在条件变量对端
cond.Single()【条件变量示例】
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68package main
import (
"fmt"
"sync"
"time"
)
//1.创建条件变量
var cond sync.Cond
func producer2(product chan<- string,index int) {
//3.使用条件变量给公共区加锁
cond.L.Lock()
//4. 判断是否已经填满缓冲区,如果填满则wait()
for len(product)==cap(product){
cond.Wait()
}
//5.执行写操作
str:=fmt.Sprintf("produce%d",index)
product<-str
fmt.Printf("这是第%d个producer进程,produce %q \n",index,str)
time.Sleep(time.Millisecond*200)
// 6.解锁
cond.L.Unlock()
//7.唤醒阻塞的对端
cond.Signal()
}
func consumer2(product <-chan string,index int) {
for{
cond.L.Lock()
for len(product)==0{
cond.Wait()
}
str :=<-product
fmt.Printf("--------这是第%d个consumer进程,consum %s \n",index,str)
cond.L.Unlock()
cond.Signal()
}
}
func main() {
product:=make(chan string,3)
// 2.指定条件变量用的锁为互斥锁
cond.L=new(sync.Mutex)
for i:=1;i<=1000;i++{
go producer2(product,i)
}
for i:=1;i<=3;i++{
go consumer2(product,i)
}
for{
;
}
}
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
