一文搞懂Go语言通道【channel】

简介: 一文搞懂Go语言通道【channel】

文章目录



前言


在Go语言中管道类似于一个数据流,每次放入或者取出一部分数据,数据取出后原通道内的数据就删除掉,在linux操作系统中管道会将函数的返回结果作为下一个函数的参数



一、Go语言通道基础概念


1.channel产生背景:


  线程之间进行通信的时候,会因为资源的争夺而产生竟态问题,为了保证数据交换的正确性,
  必须使用互斥量给内存进行加锁,go语言并发的模型是CSP,提倡通过通信共享内存,而不是
  通过共享内存而实现通信,通道恰巧满足这种需求。


2.channel工作方式


  channel类似与一个队列,满足先进先出的规则,严格保证收发数据的顺序,每一个通道只能通
  过固定类型的数据如果通道进行大型结构体、字符串的传输,可以将对应的指针传进去,尽量的节省空间


二、通道使用语法


1.通道的声明与初始化


  //定义一个通道对象使用,其中int可以换为自己需要的类型
  var a chan int  
  //初始化只有一个位置的通道(第一个参数代表通道类型,第二个参数代表通道有几个位置)
  //位置存满后新的数据将存不进来(阻塞)
  a = make(chan int,1)


2.将数据放入通道内


  取出数据使用操作符 <-
  操作符右是输入变量,操作符左是通道
  代表数据流入通道内


代码如下:


  // 声明一个通道
  var a chan int
    a <- 5


3.从通道内取出数据


  取出数据也使用操作符 <-
  操作符右是通道,操作符左是接受变量


代码如下:


  //声明一个通道类型
  var a chan int
  fmt.Println("未初始化的通道", a)
  a = make(chan int)
  // wg.Add(1)
  go func(a chan int) {
    // defer wg.Done()
    for {
      x := <-a
      fmt.Println("接收到了数据:", x)
    }
  }(a)


4.关闭通道close


  如果通道重复关闭或者关闭一个没有初始化的通道就会抛出错误
  close(a)//a为待关闭的通道


在并发函数中一次关闭通道代码如下:


// 互斥锁对象
var once sync.Once
//并发函数
//这个函数的目的是将a通道内数据乘以10发送到通道b内
func f2(a <-chan int, b chan<- int) {
  defer wg.Done()
  for {
    x, ok := <-a
    if !ok {
      break
    }
    fmt.Println(x)
    b <- x * 10
  }
  // 确保b通道只关闭一次
  once.Do(func() {
    close(b)
  })
}


三、单项通道及通道的状态分析


1.单项输出通道


var b <-chan int
• 1


2.单项输入通道


var b chan<- int



示例函数:


//单项通道一般做函数参数,作为一种规范防止通道混用
//此函数完成的功能是将a内的数据乘以10放入通道b内
func f2(a <-chan int, b chan<- int) {
  for {
    x, ok := <-a
    if !ok {
      break
    }
    fmt.Println(x)
    b <- x * 10
  }
}


3.通道的状态


channel nil未初始化 空通道 满通道 非空
接收 阻塞 阻塞 接收值 接收值
发送 阻塞 发送值 阻塞 发送值
关闭 panic 关闭成功 关闭成功 关闭成功
关闭后返回的数据 panic 返回0值 数据读完后返回零值 数据读完返回零值



四、通道死锁原因分析


注意以下情况:

在使用通道的时候,从以上表格可知有时会进入阻塞状态,如果结合我们之前介绍过的waitGroup

,如果在主函数等待使用通道的函数执行结束,而使用通道的函数并且通道陷入阻塞状态,如果有其他函数对其进行唤醒则不会死锁,如果没有其他函数可以对其进行唤醒则会抛出死锁异常。


总结


通道将数据隔离在每一份通道内,在并发的情况下可以很好的使用数据,当然要熟悉通道阻塞的几种情况,避免死锁异常。

相关文章
|
5天前
|
存储 JSON 监控
Viper,一个Go语言配置管理神器!
Viper 是一个功能强大的 Go 语言配置管理库,支持从多种来源读取配置,包括文件、环境变量、远程配置中心等。本文详细介绍了 Viper 的核心特性和使用方法,包括从本地 YAML 文件和 Consul 远程配置中心读取配置的示例。Viper 的多来源配置、动态配置和轻松集成特性使其成为管理复杂应用配置的理想选择。
23 2
|
9天前
|
JavaScript Java Go
探索Go语言在微服务架构中的优势
在微服务架构的浪潮中,Go语言以其简洁、高效和并发处理能力脱颖而出。本文将深入探讨Go语言在构建微服务时的性能优势,包括其在内存管理、网络编程、并发模型以及工具链支持方面的特点。通过对比其他流行语言,我们将揭示Go语言如何成为微服务架构中的一股清流。
|
3天前
|
Go 索引
go语言中的循环语句
【11月更文挑战第4天】
11 2
|
3天前
|
Go C++
go语言中的条件语句
【11月更文挑战第4天】
14 2
|
8天前
|
Ubuntu 编译器 Linux
go语言中SQLite3驱动安装
【11月更文挑战第2天】
30 7
|
8天前
|
关系型数据库 Go 网络安全
go语言中PostgreSQL驱动安装
【11月更文挑战第2天】
38 5
|
8天前
|
安全 Go
用 Zap 轻松搞定 Go 语言中的结构化日志
在现代应用程序开发中,日志记录至关重要。Go 语言中有许多日志库,而 Zap 因其高性能和灵活性脱颖而出。本文详细介绍如何在 Go 项目中使用 Zap 进行结构化日志记录,并展示如何定制日志输出,满足生产环境需求。通过基础示例、SugaredLogger 的便捷使用以及自定义日志配置,帮助你在实际开发中高效管理日志。
24 1
|
7天前
|
程序员 Go
go语言中的控制结构
【11月更文挑战第3天】
84 58
|
6天前
|
监控 Go API
Go语言在微服务架构中的应用实践
在微服务架构的浪潮中,Go语言以其简洁、高效和并发处理能力脱颖而出,成为构建微服务的理想选择。本文将探讨Go语言在微服务架构中的应用实践,包括Go语言的特性如何适应微服务架构的需求,以及在实际开发中如何利用Go语言的特性来提高服务的性能和可维护性。我们将通过一个具体的案例分析,展示Go语言在微服务开发中的优势,并讨论在实际应用中可能遇到的挑战和解决方案。
|
7天前
|
存储 编译器 Go
go语言中的变量、常量、数据类型
【11月更文挑战第3天】
24 9