头图

前言
在 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)

}

以上输出结果为

图片

图片

是因为无缓存线写之后,会阻塞
有缓存channel
go 代码解读复制代码package main

import (

_ "fmt"
"log"

)

func main() {

var chan2 = make(chan int, 1)
chan2 <- 1
data := <-chan2
log.Println("data的值为:", data)

}

以上输出结果为

图片

但是超过定义的缓存,就会发生死锁
go 代码解读复制代码package main

import (

_ "fmt"
"log"

)

func main() {

var chan2 = make(chan int, 1)
chan2 <- 1
chan2 <- 2
data := <-chan2
log.Println("data的值为:", data)

}

以上输出结果为

图片

从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)

}

以上结果为

图片

但是要注意的是,在使用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)

}

以上输出结果为

图片

channel只读没写,也会报死锁问题
go 代码解读复制代码package main

import "fmt"

func main() {

ch := make(chan int64)
data := <-ch
fmt.Println(data)

}

以上结果为

图片

使用切片的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("==============执行")

}

图片

转载来源:https://juejin.cn/post/7385583777731969058


运维社
12 声望4 粉丝