go中的chan管道机制

科技公元 后端 2024-08-26

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,例如

有缓存 channelgo
代码解读
复制代码
package main import ( _ "fmt" "log" ) func main() { var chan2 = make(chan int) chan2 <- 1 data := <-chan2 log.Println("data的值为:", data) }

以上输出结果为

go中的chan管道机制go中的chan管道机制是因为无缓存线写之后,会阻塞

有缓存channelgo
代码解读
复制代码
package main import ( _ "fmt" "log" ) func main() { var chan2 = make(chan int, 1) chan2 <- 1 data := <-chan2 log.Println("data的值为:", data) }

以上输出结果为

go中的chan管道机制但是超过定义的缓存,就会发生死锁go

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

以上输出结果为

go中的chan管道机制

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

以上结果为

go中的chan管道机制但是要注意的是,在使用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) }

以上输出结果为

go中的chan管道机制channel只读没写,也会报死锁问题go

代码解读
复制代码
package main import "fmt" func main() { ch := make(chan int64) data := <-ch fmt.Println(data) }

以上结果为

go中的chan管道机制使用切片的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("==============执行") }

go中的chan管道机制

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

Apipost 私有化火热进行中

评论