Go Channel 的基本运用和原理分析

简介: Go 在 goroutine 的通信经常会提及的设计思想是:不要通过共享内存的方式进行通信,而应该通过通信的方式共享内存。这和 Java 语言不通,Java 中多个线程传递数据的方式一般都是通过共享内存或者其他共享资源的方式解决线程竞争问题。

Go 在 goroutine 的通信经常会提及的设计思想是:不要通过共享内存的方式进行通信,而应该通过通信的方式共享内存。这和 Java 语言不通,Java 中多个线程传递数据的方式一般都是通过共享内存或者其他共享资源的方式解决线程竞争问题。

Channel

基本操作

ch := make(chan int, 10) // 创建 channel
ch <- 1 // 写入
v := <- ch // 读取
  • 使用 make 初始化 channel ,并可以设置容量 ,10 就是容量 capacity 表示 Channel 容纳的最多元素的数量,即 Channel 缓存的大小。
  • 如果没有设置容量,或者容量是为0 ,那说明没有缓存,即为同步。发送和接收需要同步进行,否则容易发生堵塞
  • 可定义只读 channel 或只写 channel
ch2 := make(<-chan int) // 只可以用来接收 int 类型的数据
ch3 := make(chan<- int) // 只可以用来发送 int 类型的数据

常用操作

for rang 读取 channel

缓存 channel 需要不断读取时,可以使用 for range 。当channel 关闭了,for 循环就会自动退出,这样就不需要再进行监控。

ch := make(chan int, 10)
for x := range ch {
    fmt.Println(x)
}

_, ok 判断 channel 是否关闭

读已关闭的 channel 会得到零值,所以可以使用该方式先判断是否已关闭。若 ok=true 则表示读到数据,chan 未关闭;若 ok=false 则表示chan 已关闭,无数据读到。

if v,ok := <-ch; ok{
     fmt.Println(v)
}

select 处理多个 channel

当有多个通道,需要对多个 channel 进行监控时,可使用 select 。需要注意 select 只处理伟阻塞的 case ,若通道为 nil 时对应的 case 将会堵塞。

ch := make(chan int, 10)
ch1 := make(chan int, 10)
func doLinsen(){
    select {
        case <-ch:
            fmt.Println(1)
        case <-ch1:
            fmt.Println(2)
    }
}

channel 控制读写权限

控制 channel 只读或者只写

// 只读 readCh的数据,声明为 <-chan int
func consumer(readCh <-chan int) {
    for x:= range readCh{
        fmt.Println(x)
    }
}

使用 time 实现 channel 无阻塞读写

select + channel 方法处理 channel 时,为操作加上超时的处理

func consumer(){
    select {
        case ch <-x:
          fmt.Println(ch)
        case time.After(time.Microsecond): // 超时处理
            return errors.New("read time out")
    }
}

使用 chan struct{} 作为信号 channel

协程通过传递退出信号,告知协程退出,而这个退出信号就可以使用 空 struct。

type Handler struct {
    stopCh chan struct{}
    reqCh chan *Request
}

应用场景

channel 主要运用在数据流动的场景中:

  • 消息传递
  • 事件消息订阅与广播
  • 并发控制
  • 同步与异步
  • 任务分发

Channel 底层原理

type hchan struct {
    qcount   uint           // total data in the queue
    dataqsiz uint           // size of the circular queue
    buf      unsafe.Pointer // points to an array of dataqsiz elements
    elemsize uint16
    closed   uint32
    elemtype *_type // element type
    sendx    uint   // send index
    recvx    uint   // receive index
    recvq    waitq  // list of recv waiters
    sendq    waitq  // list of send waiters

    // lock protects all fields in hchan, as well as several
    // fields in sudogs blocked on this channel.
    //
    // Do not change another G's status while holding this lock
    // (in particular, do not ready a G), as this can deadlock
    // with stack shrinking.
    lock mutex
}

如上,Channel 的结构体是 hchan。含有11个字段:

  • buf 是用来存储缓存数据,是个循环链表
  • sendx 和 recvx 是用来记录 buf 循环链表中 发送或接收的索引
  • lock 是互斥锁
  • recvq 和 sendq 是接收和发送的协程队列。

参考资料:

目录
相关文章
|
2月前
|
存储 Go 开发者
Go语言中的并发编程与通道(Channel)的深度探索
本文旨在深入探讨Go语言中并发编程的核心概念和实践,特别是通道(Channel)的使用。通过分析Goroutines和Channels的基本工作原理,我们将了解如何在Go语言中高效地实现并行任务处理。本文不仅介绍了基础语法和用法,还深入讨论了高级特性如缓冲通道、选择性接收以及超时控制等,旨在为读者提供一个全面的并发编程视角。
|
2月前
|
安全 Go 数据处理
Go语言中的并发编程:掌握goroutine和channel的艺术####
本文深入探讨了Go语言在并发编程领域的核心概念——goroutine与channel。不同于传统的单线程执行模式,Go通过轻量级的goroutine实现了高效的并发处理,而channel作为goroutines之间通信的桥梁,确保了数据传递的安全性与高效性。文章首先简述了goroutine的基本特性及其创建方法,随后详细解析了channel的类型、操作以及它们如何协同工作以构建健壮的并发应用。此外,还介绍了select语句在多路复用中的应用,以及如何利用WaitGroup等待一组goroutine完成。最后,通过一个实际案例展示了如何在Go中设计并实现一个简单的并发程序,旨在帮助读者理解并掌
|
2月前
|
Go API 数据库
Go 语言中常用的 ORM 框架,如 GORM、XORM 和 BeeORM,分析了它们的特点、优势及不足,并从功能特性、性能表现、易用性和社区活跃度等方面进行了比较,旨在帮助开发者根据项目需求选择合适的 ORM 框架。
本文介绍了 Go 语言中常用的 ORM 框架,如 GORM、XORM 和 BeeORM,分析了它们的特点、优势及不足,并从功能特性、性能表现、易用性和社区活跃度等方面进行了比较,旨在帮助开发者根据项目需求选择合适的 ORM 框架。
144 4
|
2月前
|
中间件 Go API
Go语言中几种流行的Web框架,如Beego、Gin和Echo,分析了它们的特点、性能及适用场景,并讨论了如何根据项目需求、性能要求、团队经验和社区支持等因素选择最合适的框架
本文概述了Go语言中几种流行的Web框架,如Beego、Gin和Echo,分析了它们的特点、性能及适用场景,并讨论了如何根据项目需求、性能要求、团队经验和社区支持等因素选择最合适的框架。
140 1
|
2月前
|
安全 Go 调度
探索Go语言的并发模型:goroutine与channel
在这个快节奏的技术世界中,Go语言以其简洁的并发模型脱颖而出。本文将带你深入了解Go语言的goroutine和channel,这两个核心特性如何协同工作,以实现高效、简洁的并发编程。
|
2月前
|
Go 调度 开发者
探索Go语言中的并发模式:goroutine与channel
在本文中,我们将深入探讨Go语言中的核心并发特性——goroutine和channel。不同于传统的并发模型,Go语言的并发机制以其简洁性和高效性著称。本文将通过实际代码示例,展示如何利用goroutine实现轻量级的并发执行,以及如何通过channel安全地在goroutine之间传递数据。摘要部分将概述这些概念,并提示读者本文将提供哪些具体的技术洞见。
|
2月前
|
安全 Go 开发者
代码之美:Go语言并发编程的优雅实现与案例分析
【10月更文挑战第28天】Go语言自2009年发布以来,凭借简洁的语法、高效的性能和原生的并发支持,赢得了众多开发者的青睐。本文通过两个案例,分别展示了如何使用goroutine和channel实现并发下载网页和构建并发Web服务器,深入探讨了Go语言并发编程的优雅实现。
41 2
|
3月前
|
安全 Go 调度
探索Go语言的并发之美:goroutine与channel
在这个快节奏的技术时代,Go语言以其简洁的语法和强大的并发能力脱颖而出。本文将带你深入Go语言的并发机制,探索goroutine的轻量级特性和channel的同步通信能力,让你在高并发场景下也能游刃有余。
|
3月前
|
存储 安全 Go
探索Go语言的并发模型:Goroutine与Channel
在Go语言的多核处理器时代,传统并发模型已无法满足高效、低延迟的需求。本文深入探讨Go语言的并发处理机制,包括Goroutine的轻量级线程模型和Channel的通信机制,揭示它们如何共同构建出高效、简洁的并发程序。
|
3月前
|
存储 Go 调度
深入理解Go语言的并发模型:goroutine与channel
在这个快速变化的技术世界中,Go语言以其简洁的并发模型脱颖而出。本文将带你穿越Go语言的并发世界,探索goroutine的轻量级特性和channel的同步机制。摘要部分,我们将用一段对话来揭示Go并发模型的魔力,而不是传统的介绍性文字。