go中的chan管道机制

简介: Go 语言推崇通过通信来共享内存而非共享内存来通信,其中 Channel(通常简写为 `chan`)作为关键机制之一,允许两个并发执行的协程之间进行同步和数据交换。`chan` 是一种引用类型,可通过 `make` 函数创建,

前言

在 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("==============执行")
}

总结

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


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

相关文章
|
3月前
|
存储 缓存 Java
深入理解 go chan
深入理解 go chan
66 0
|
监控 Go C++
GO 中 Chan 实现原理分享
GO 中 Chan 实现原理分享
134 0
|
Go
Go使用chan或context退出协程
Go使用chan或context退出协程
234 1
深入浅出Go语言通道chan类型
深入浅出Go语言通道chan类型
深入浅出Go语言通道chan类型
深入浅出Go语言通道chan类型
347 0
深入浅出Go语言通道chan类型
|
安全 Java Go
Go语学习笔记 - chan | 从零开始Go语言
Go语学习笔记 - chan | 从零开始Go语言
|
存储 Go C++
Go 中slice, map, chan, strcuct 是值传递么?
Go 中slice, map, chan, strcuct 是值传递么?
330 0
|
Go 开发工具 git
Golang之chan/goroutine(转)
原文地址:http://tchen.me/posts/2014-01-27-golang-chatroom.html?utm_source=tuicool&utm_medium=referral 看了一上午写得很好,可以拿来试试刀 最近在team内部培训golang,目标是看看golang能否被C工程师快速掌握。
1613 0
|
6天前
|
存储 JSON 监控
Viper,一个Go语言配置管理神器!
Viper 是一个功能强大的 Go 语言配置管理库,支持从多种来源读取配置,包括文件、环境变量、远程配置中心等。本文详细介绍了 Viper 的核心特性和使用方法,包括从本地 YAML 文件和 Consul 远程配置中心读取配置的示例。Viper 的多来源配置、动态配置和轻松集成特性使其成为管理复杂应用配置的理想选择。
23 2
|
4天前
|
Go 索引
go语言中的循环语句
【11月更文挑战第4天】
13 2