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使用内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • golang中for循环遍历channel时需要注意的问题详解

    前言 for循环是Go语言唯一的循环结构,最近在做一个基于RabbitMQ的应用,由于官方的qos没有golang的版本,所以出了一点问题. 问题代码如下: _, ch, err := component.NewRabbitMQ() if err != nil { panic(err) } if err := ch.Qos(10, 0, true); err != nil { panic(err) } msgs, err := ch.Consume("push", "&quo

  • Golang中channel使用的一些小技巧

    关闭2次 复制代码 代码如下: ch := make(chan bool) close(ch) close(ch)  // 这样会panic的,channel不能close两次 读取的时候channel提前关闭了 复制代码 代码如下: ch := make(chan string) close(ch) i := <- ch // 不会panic, i读取到的值是空 "",  如果channel是bool的,那么读取到的是false 向已经关闭的channel写数据 复制代码 代码

  • golang中单向channel的语法介绍

    本文主要给大家介绍的是关于golang单向channel语法的相关内容,分享出来供大家参考学习,下面话不多说,来一起看看详细的介绍: 今天闲来无事补充一下golang的语法知识,想起来看看context的用法,结果碰到了一个没见过的channel语法: // A Context carries a deadline, cancelation signal, and request-scoped values // across API boundaries. Its methods are sa

  • Golang优雅关闭channel的方法示例

    前言 最近使用go开发后端服务,服务关闭需要保证channel中的数据都被读取完,理由很简单,在收到系统的中断信号后,系统需要做收尾工作,保证channel的数据都要被处理掉,然后才可以关闭系统.但实现起来没那么简单,下面来一起看看详细的介绍吧. 关于Go channel设计和规范的批评: 在不能更改channel状态的情况下,没有简单普遍的方式来检查channel是否已经关闭了 关闭已经关闭的channel会导致panic,所以在closer(关闭者)不知道channel是否已经关闭的情况下去

  • golang判断chan channel是否关闭的方法

    本文实例讲述了golang判断chan channel是否关闭的方法.分享给大家供大家参考,具体如下: 群里有朋友问,怎么判断chan是否关闭,因为close的channel不会阻塞,并返回类型的nil值,会导致死循环.在这里写个例子记录一下,并且分享给大家 如果不判断chan是否关闭 Notice: 以下代码会产生死循环 复制代码 代码如下: package main import (     "fmt" ) func main() {     c := make(chan int,

  • golang开发中channel使用

    channel[通道]是golang的一种重要特性,正是因为channel的存在才使得golang不同于其它语言.channel使得并发编程变得简单容易有趣. channel的概念和语法 一个channel可以理解为一个先进先出的消息队列.channel用来在协程[goroutine]之前传递数据,准确的说,是用来传递数据的所有权.一个设计良好的程序应该确保同一时刻channel里面的数据只会被同一个协程拥有,这样就可以避免并发带来的数据不安全问题[data races]. 正文 channel

  • 详解golang开发中select多路选择

    select 是 Golang 中的一个控制结构,语法上类似于switch 语句,只不过select是用于 goroutine 间通信的 ,每个 case 必须是一个通信操作,要么是发送要么是接收,select 会随机执行一个可运行的 case.如果没有 case 可运行,goroutine 将阻塞,直到有 case 可运行. select 多路选择 select写法上跟switch case的写法基本一致,只不过golang的select是通信控制语句.select的执行必须有通信的发送或者接

  • Golang开发中如何解决共享变量问题

    目录 1.什么是竞态 2.如何消除竞态 3.Go 提供的并发工具 3.1 互斥锁 3.2 读写互斥锁 3.3 Once 3.4 竞态检测器 4.小结 Go 语言中 goroutine + channel 通过通信的方式来共享内存,从而实现并发编程. 但同时 Go 也提供了传统通过共享变量,也就是共享内存的方式来实现并发.这篇文章会介绍 Go提供的相关机制. 1.什么是竞态 在一个 Go 程序运行起来之后,会有很多的 goroutine 同时运行,每个 goroutine 中代码的执行是顺序的,如

  • 十个Golang开发中应该避免的错误总结

    目录 不检查错误 必要时不使用指针 没有正确使用channel 不释放资源 没有使用正确的数据结构 错误地使用循环变量 不处理竞赛条件 没有使用正确的类型 不使用Go的标准库 没有有效地使用interface 没有有效利用测试 Go是一种静态类型的.并发的.垃圾收集的编程语言,由谷歌开发.近年来,由于它的简单性.性能和对并发的强大支持,它已经获得了普及.尽管它很简单,但开发人员在编写Go代码时仍有一些常见的错误.下面是Go语言中需要避免的十大坏错误,以及每个错误的代码示例: 不检查错误 Go函数

  • 详解golang开发中http请求redirect的问题

    这两天在开发项目的时候遇到了一个问题,请求了一个URL,它会302到另一个地址,本意上只是想检查这个URL是否会做3XX的redirect跳转,结果每次reqeust都会返回最后一跳的结果.后来就看了下源码,了解下请求跳转的机制 实现代码 看下实现的简单代码 func main() { client := &http.Client{} url := "http://www.qq.com" reqest, err := http.NewRequest("GET"

  • Golang开发中常用的代码片段汇总

    本文主要总结的是我在编写golang应用时使用到的代码片段,提供出来以备以后使用,也给需要的朋友们以参考学习,下面话不多说,来看看详细介绍: 一.通过http package发送user:passwd信息 发送类似于 curl -u 的请求 client := &http.Client{} req, err := http.NewRequest("GET", <url>, nil) req.SetBasicAuth(<username>, <use

  • 详解Golang中Channel的用法

    如果说goroutine是Go语言程序的并发体的话,那么channels则是它们之间的通信机制.一个channel是一个通信机制,它可以让一个goroutine通过它给另一个goroutine发送值信息. 1 创建channel 每个channel都有一个特殊的类型,也就是channels可发送数据的类型.一个可以发送int类型数据 的channel一般写为chan int.使用内置的make函数,如果第二个参数大于0,则表示创建一个带缓存的channel. ch := make(chan in

  • Golang中channel的原理解读(推荐)

    数据结构 channel的数据结构在$GOROOT/src/runtime/chan.go文件下: type hchan struct { qcount uint // 当前队列中剩余元素个数 dataqsiz uint // 环形队列长度,即可以存放的元素个数 buf unsafe.Pointer // 环形队列指针 elemsize uint16 // 每个元素的大小 closed uint32 // 标记是否关闭 elemtype *_type // 元素类型 sendx uint //

  • golang 中 channel 的详细使用、使用注意事项及死锁问题解析

    目录 什么是channel管道 channel的基本使用 定义和声明 操作channel的3种方式 单向channel 带缓冲和不带缓冲的channel 不带缓冲区channel 带缓冲区channel 判断channel是否关闭 rangeandclose for读取channel select使用 channel的一些使用场景 1.作为goroutine的数据传输管道 2.同步的channel 3.异步的channel 4.channel超时处理 使用channel的注意事项及死锁分析 未初

  • Golang中Channel实战技巧与一些说明

    目录 Channel 的一些实战说明 关于 close Channel close Channel 的一些说明 v, ok := <-ch 判断是否 close 优雅判断是否 close 的封装 for-range 读取 Channel 数据 select 读写 Channel 数据 Channel 的读写超时机制[select + timeout] TryEnqueue 无阻塞写 Channel 数据 Channel 常见错误和根因分析 fatal error: all goroutines

随机推荐