go中的chan管道机制

前言

在 Go 语言中,提倡通过通信来共享内存,而不是通过共享内存来通信,go中的Channel(一般简写为 chan) 管道提供了一种机制,它在两个并发执行的协程之间进行同步,并通过传递与该管道元素类型相符的值来进行通信,可以用来两个不同的协程之间共享数据

chan使用
chan类型

channel是一种类型,一种引用类型,声明类型时,可以使用

 

go

代码解读

复制代码

var chan2 = make(chan int)

或者

 

go

代码解读

复制代码

var chan2 = make(chan int64)

等等,创建chan用make实现,并且channel遵循先进先出原则

chan使用

chan在两个不同的协程之间通讯

 

go

代码解读

复制代码

package main import ( "fmt" _ "fmt" "time" ) func main() { var chan2 = make(chan int) go say(chan2) go say1(chan2) time.Sleep(5 * time.Second) } func say(a chan<- int) { for i := 0; i < 100; i++ { a <- i } } func say1(a <-chan int) { for i := 0; i < 100; i++ { data := <-a fmt.Println(data) } }

chan使用注意

chan分为无缓存 channel 和有缓存 channel,例如

有缓存 channel
 

go

代码解读

复制代码

package main import ( _ "fmt" "log" ) func main() { var chan2 = make(chan int) chan2 <- 1 data := <-chan2 log.Println("data的值为:", data) }

以上输出结果为

image.png

image.png

是因为无缓存线写之后,会阻塞

有缓存channel
 

go

代码解读

复制代码

package main import ( _ "fmt" "log" ) func main() { var chan2 = make(chan int, 1) chan2 <- 1 data := <-chan2 log.Println("data的值为:", data) }

以上输出结果为

image.png

但是超过定义的缓存,就会发生死锁

 

go

代码解读

复制代码

package main import ( _ "fmt" "log" ) func main() { var chan2 = make(chan int, 1) chan2 <- 1 chan2 <- 2 data := <-chan2 log.Println("data的值为:", data) }

以上输出结果为

image.png

从chan取值

使用range可以从channel取值。如

 

go

代码解读

复制代码

package main import "log" func main() { ch := make(chan int64) go say(ch) for i := range ch { data := i log.Println(data) } } func say(ch chan int64) { for i := 0; i < 100; i++ { ch <- int64(i) } close(ch) }

以上结果为

image.png

但是要注意的是,在使用range遍历时,需要关闭管道,否则会报死锁

 

go

代码解读

复制代码

package main import "log" func main() { ch := make(chan int64) go say(ch) for i := range ch { data := i log.Println(data) } } func say(ch chan int64) { for i := 0; i < 100; i++ { ch <- int64(i) } //close(ch) }

以上输出结果为

image.png

channel只读没写,也会报死锁问题

 

go

代码解读

复制代码

package main import "fmt" func main() { ch := make(chan int64) data := <-ch fmt.Println(data) }

以上结果为

image.png

使用切片的channel就不会报死锁

 

go

代码解读

复制代码

package main import ( "fmt" "time" ) func main() { channels := make([]chan int, 2) for i := 0; i < 2; i++ { go func(ch chan int) { time.Sleep(time.Second) ch <- 1 }(channels[i]) } for ch := range channels { fmt.Println("执行结果为:", ch) } fmt.Println("执行结束=====================") }

chnnel可读可写

channel 可以分为 3 种类型:

  • 只读 channel,单向 channel
  • 只写 channel,单向 channel
  • 可读可写 channel 默认情况下,都是可读可写的,如
 

go

代码解读

复制代码

ch := make(chan int64)

定义一个可读管道

 

css

代码解读

复制代码

func say(ch <-chan int) { for i := 0; i < 100; i++ { data := <-ch log.Println("结果为:", data) } }

定义一个只可写通道

 

css

代码解读

复制代码

func say1(ch chan<- int) { for i := 0; i < 100; i++ { ch <- i } }

使用如下

 

go

代码解读

复制代码

package main import ( "log" "time" ) func main() { var ch = make(chan int) go say(ch) go say1(ch) time.Sleep(5 * time.Second) } func say(ch <-chan int) { for i := 0; i < 100; i++ { data := <-ch log.Println("结果为:", data) } } func say1(ch chan<- int) { for i := 0; i < 100; i++ { ch <- i } }

chan超时

chan配合select机制可以设置阻塞超时

 

go

代码解读

复制代码

package main import ( "fmt" "time" ) func main() { var ch = make(chan int) go say(ch) select { case data, ok := <-ch: fmt.Println(data, ok) case <-time.After(3 * time.Second): fmt.Println("================超时") } } func say(ch chan int) { time.Sleep(5 * time.Second) ch <- 1 fmt.Println("==============执行") }

image.png

总结

合理的使用channel,在并发中更好的进行写成之间的通讯

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值