通道技巧,关闭通道后还能继续用

简介: 通道技巧,关闭通道后还能继续用

概述

在 Go 语言中,通道(Channel)是一种强大的并发机制,但很多开发者在关闭通道后是否还能使用存在疑惑。

本文将探讨在关闭通道后继续利用通道的技巧,解释其原理,并通过实例代码演示在实际应用中的巧妙用法。


 

1. 通道关闭的基本原理

在 Go 语言中,通过 close 函数可以关闭一个通道。

关闭通道后,将不能再向通道发送数据,但仍然可以从通道接收数据。

这是因为关闭通道后,接收者仍然可以读取通道中已有的数据,直到通道中的数据被全部读取完毕。


 

2. 关闭通道后的读取


package main
import (  "fmt"  "time")
func main() {  ch := make(chan int, 3)
  go func() {    defer close(ch)    for i := 1; i <= 3; i++ {      ch <- i      time.Sleep(time.Second)    }  }()
  // 读取通道中的数据  for {    select {    case num, ok := <-ch:      if !ok {        fmt.Println("通道已关闭")        return      }      fmt.Println("接收到数据:", num)    default:      // 可以进行其他操作      time.Sleep(500 * time.Millisecond)    }  }}

在示例中,创建了一个带缓冲的通道,并在一个 goroutine 中向通道发送数据,每发送一次就休眠 1 秒。

在主 goroutine 中,通过 select 语句监听通道的数据,并在通道关闭后打印提示信息。


 

3. 关闭通道后的写入


package main
import (  "fmt"  "time")
func main() {  ch := make(chan int, 3)    go func() {    defer close(ch)    for i := 1; i <= 3; i++ {      ch <- i      time.Sleep(time.Second)    }  }()
  // 写入数据到已关闭的通道  for i := 4; i <= 6; i++ {    select {    case ch <- i:      fmt.Println("写入数据:", i)    default:      fmt.Println("通道已关闭,写入失败")    }  }}

在上述示例中,同样创建了一个带缓冲的通道,并在一个 goroutine 中向通道发送数据。

在主 goroutine 中,尝试向已关闭的通道写入数据,并通过 select 语句判断通道的状态,实现对写入的合理控制。


 

4. 应用场景:扇出与扇入

4.1 扇出

扇出是指将一个通道的数据分发给多个 goroutine 进行处理。

关闭通道后,接收者可以继续处理通道中的数据,实现数据的扇出。


package main
import (  "fmt"  "sync"  "time")
func main() {  ch := make(chan int, 5)
  go func() {    defer close(ch)    for i := 1; i <= 5; i++ {      ch <- i      time.Sleep(500 * time.Millisecond)    }  }()
  var wg sync.WaitGroup  for i := 0; i < 3; i++ {    wg.Add(1)    go func(id int) {      defer wg.Done()      for {        select {        case num, ok := <-ch:          if !ok {            fmt.Printf("协程%d:通道已关闭\n", id)            return          }          fmt.Printf("协程%d:接收到数据:%d\n", id, num)        default:          // 可以进行其他操作          time.Sleep(300 * time.Millisecond)        }      }    }(i)  }  wg.Wait()}

在上面示例中,创建了一个带缓冲的通道,并在一个 goroutine 中向通道发送数据。

然后启动了三个协程,每个协程通过 select 语句监听通道的数据,实现了数据的扇出。

4.2 扇入

扇入是指将多个通道的数据汇总到一个通道中。

关闭通道后,接收者可以继续从已关闭的多个通道中读取数据,实现数据的扇入。


package main
import (  "fmt"  "sync"  "time")
func main() {  ch1 := make(chan int, 3)  ch2 := make(chan int, 3)  outCh := make(chan int, 6)
  go func() {    defer close(ch1)    for i := 1; i <= 3; i++ {      ch1 <- i      time.Sleep(500 * time.Millisecond)    }  }()
  go func() {    defer close(ch2)    for i := 4; i <= 6; i++ {      ch2 <- i      time.Sleep(500 * time.Millisecond)    }  }()
  var wg sync.WaitGroup  wg.Add(2)
  go func() {    defer wg.Done()    for {      select {      case num, ok := <-ch1:        if !ok {          fmt.Println("通道ch1已关闭")          return        }        outCh <- num      default:        // 可以进行其他操作        time.Sleep(300 * time.Millisecond)      }    }  }()
  go func() {    defer wg.Done()    for {      select {      case num, ok := <-ch2:        if !ok {          fmt.Println("通道ch2已关闭")          return        }        outCh <- num      default:        // 可以进行其他操作        time.Sleep(300 * time.Millisecond)      }    }  }()
  go func() {    wg.Wait()    close(outCh)  }()
  for num := range outCh {    fmt.Printf("接收到合并通道的数据:%d\n", num)  }}

在上面示例中,创建了两个带缓冲的通道 ch1ch2 ,并在两个 goroutine 中向这两个通道发送数据。

然后启动了两个协程,每个协程通过 select 语句监听各自通道的数据,并将数据写入一个输出通道 outCh 中,最后在主 goroutine 中读取outCh 中的数据。


 

5. 总结

通过本文的讲解和示例代码,了解了在 Go 语言中关闭通道后继续使用通道的技巧。

这一特性可以在一些实际应用场景中发挥重要作用,如扇出与扇入。

关闭通道后继续使用通道看起来有些反直觉,但是这种设计提供了一定的灵活性。

在编码时,还是要考虑通道的同步逻辑,谨慎使用这种特性,避免引起数据竞争等问题。

目录
相关文章
|
5月前
流的关闭的几种方式
流的关闭的几种方式
|
11月前
|
Windows
USB 设备:自定义批量传输及实现
USB 设备:自定义批量传输及实现
709 0
|
算法 物联网
设备通过mqtt通道的动态免预注册
一型一密认证方式下,同一产品下所有设备可以烧录相同的设备标志信息,即所有设备包含相同的产品证书(ProductKey和ProductSecret)。设备发送激活请求时,物联网平台会进行身份确认,认证通过后,下发设备接入所需信息。
342 0
|
存储 算法 安全
设备通过mqtt通道的动态预注册
在物联网平台为产品开启动态注册功能后,直连设备可使用一型一密安全认证方式完成动态注册,通过MQTT通信协议连接物联网平台。设备先基于TLS建立与物联网平台的连接,获取MQTT连接所需的设备密钥,再断开连接,然后重新建立MQTT连接进行通信。
448 1
|
缓存
多线程之间的通信~~~管道通道
多线程之间的通信~~~管道通道
188 0
|
芯片
DRV8848通道输出不正常原因
DRV8848通道输出不正常原因
|
网络安全 数据中心 网络架构
操作高速通道 配置健康检查,只需四步!
阿里云每两秒从健康检查IP地址向本地数据中心中的客户侧互联IP发送一个ping报文,如果某条物理专线上连续8个ping报文都无法得到回复,则将流量切换至另一条链路。
799 0
LiveVideoStackCon 2018 注册通道即将关闭
LiveVideoStackCon 2018 售票通道将于今晚24:00正式关闭,点击【阅读原文】即可进行购票注册。
755 0

热门文章

最新文章