golang开发中channel使用

 更新时间:2020年09月27日 08:27:21   作者:飞翔码农  
channel[通道]是golang的一种重要特性,正是因为channel的存在才使得golang不同于其它语言。这篇文章主要介绍了golang开发中channel使用,需要的朋友可以参考下

channel[通道]是golang的一种重要特性,正是因为channel的存在才使得golang不同于其它语言。channel使得并发编程变得简单容易有趣。

channel的概念和语法

一个channel可以理解为一个先进先出的消息队列。channel用来在协程[goroutine]之前传递数据,准确的说,是用来传递数据的所有权。一个设计良好的程序应该确保同一时刻channel里面的数据只会被同一个协程拥有,这样就可以避免并发带来的数据不安全问题[data races]。

正文

channel主要是用于多个goroutine之间通信

channel语法

channel是引用类型,需要实用make来创建channel,如下
make(chan Type, [buffer])
chan Type 通道的类型
buffer 是可选参数,代表通道缓冲区的大小(省略则代表无缓冲)
向channel里面写入数据使用 <- 符号

q := make(chan bool)
q<-true

从channel里面读取数据也是使用 <- 符号,只不过写入的channel在右边,读取的时候channel在左边。意思跟方向是一致的,一个是数据进入channel,一个是数据从channel出去

q := make(chan bool)
<-q

有缓冲channel的使用

我们一直使用的无缓冲的channel,今天主要学习下有缓存的channel。
无缓冲的channel,写入数据后一定要有goroutine 从channel读取数据后再写入,否则程序会panic。

func main() {
	ch := make(chan int)
	ch<-1
}

fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan send]:

有缓冲的channel,可以写入缓冲大小个数据,可以没有goroutine从channel读取。

func main() {
	ch := make(chan int,2)
	ch<-1
	ch<-2
}


Process finished with exit code 0

执行结果跟预期是一致的。

有缓冲大小的channel使用场景

假如我们有一个任务需要10个goroutine去调度执行,只要有一个goroutine执行完毕,调度就应该结束。我们看下伪代码

func test(wg *sync.WaitGroup,ch chan int,i int) {
	fmt.Println("test code")
	ch<-i
}

func main() {
	fmt.Println("start",runtime.NumGoroutine())
	ch := make(chan int)
	wg := new(sync.WaitGroup)
	for i:=0;i<10;i++ {
		wg.Add(1)
		go test(wg,ch,i)
	}
	fmt.Println(<-ch)
	fmt.Println("end",runtime.NumGoroutine())
	wg.Done()
}

start 1
test code
9
end 10

从执行结果上看,是第9个goroutine首先执行完毕了。程序也正常退出了。但是我们看到,加上主goroutine,内存中一共有11个goroutine,程序退出的时候还有10个goroutine,减去一个主goroutine,还有9个goroutine没有退出,这个对程序来说是不允许,可能会泄漏或者长期占用资源不释放。

但是我们如果使用了有缓冲的channel,就可以利用channel的缓冲机制正常退出全部的goroutine了。
看下代码

func test(wg *sync.WaitGroup,ch chan int,i int) {
	ch<-i
}

func main() {
	fmt.Println("start",runtime.NumGoroutine())
	ch := make(chan int, 10)
	wg := new(sync.WaitGroup)
	for i:=0;i<10;i++ {
		wg.Add(1)
		go test(wg,ch,i)
	}
	fmt.Println(<-ch,"success")
	for i:= 0;i<9;i++ {
	 fmt.Println(<-ch)
	}
	fmt.Println("end",runtime.NumGoroutine())
	wg.Done()
}

start 1
0 success
1
2
4
3
5
6
7
8
9
end 1

Process finished with exit code 0

打印success的时候,第一个goroutine已经将任务完成,循环9次将channel里面的数据读取出来,保证创建的goroutine都不会阻塞能够正常退出来。

到此这篇关于golang开发中channel使用的文章就介绍到这了,更多相关golang channel使用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Go语言程序开发gRPC服务

    Go语言程序开发gRPC服务

    这篇文章主要为大家介绍了Go语言程序开发gRPC服务,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-06-06
  • Golang中map的三种声明定义方式实现

    Golang中map的三种声明定义方式实现

    本文主要介绍了Golang中map的三种声明定义方式实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-02-02
  • go实现grpc四种数据流模式

    go实现grpc四种数据流模式

    这篇文章主要为大家介绍了go实现grpc四种数据流模式,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步早日升职加薪
    2022-04-04
  • 详解Go是如何优雅的进行内存管理

    详解Go是如何优雅的进行内存管理

    Go语言抛弃C/C++中的开发者管理内存的方式,实现了主动申请与主动释放管理,增加了逃逸分析和垃圾回收,将开发者从内存管理中释放出来,作为进阶的Go开发,了解掌握Go的内存管理还是很有必要的
    2023-09-09
  • Golang在Window环境使用Imagick7的过程

    Golang在Window环境使用Imagick7的过程

    这篇文章主要介绍了Golang在Window环境使用Imagick7的过程,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2023-11-11
  • go开源Hugo站点渲染之模板词法解析

    go开源Hugo站点渲染之模板词法解析

    这篇文章主要为大家介绍了go开源Hugo站点渲染之模板词法解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-02-02
  • go语言中GoMock安装使用详解

    go语言中GoMock安装使用详解

    这篇文章主要为大家介绍了go语言中GoMock安装使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-11-11
  • Golang 数据库操作(sqlx)和不定字段结果查询

    Golang 数据库操作(sqlx)和不定字段结果查询

    本文主要介绍了Golang 数据库操作(sqlx)和不定字段结果查询,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-09-09
  • golang gorm更新日志执行SQL示例详解

    golang gorm更新日志执行SQL示例详解

    这篇文章主要为大家介绍了golang gorm更新日志执行SQL示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步早日升职加薪
    2022-04-04
  • 详解Golang中的交叉编译

    详解Golang中的交叉编译

    在 Golang 中,交叉编译指的是在同一台机器上生成针对不同操作系统或硬件架构的二进制文件,这在开发跨平台应用或构建特定平台的发布版本时非常有用,本文就详细的给大家介绍一下Golang中的交叉编译,需要的朋友可以参考下
    2023-08-08

最新评论