golang channel管道使用示例解析

目录
  • 定义channel管道
  • channel管道塞值和取值
  • 通过channel管道实现同步,和数据交互
  • 无缓冲的channel
  • 有缓冲的channel管道
  • 关闭channel管道
  • 单向channel管道,读写分离
  • 管道消费者生产者模型

定义channel管道

定义一个channel时,也需要定义发送到管道的值类型。channel可以使用内置的make()函数来创建:

var ch = make(chan int) //等价于:make(chan Type,0)
var ch = make(chan Type,capacity)

channel管道塞值和取值

ch <- 666  //向ch管道塞入666
<- ch  // 向ch管道接收值,并丢弃
x := <-ch  //向ch管道中接收数据,并复制给x
x, ok := <-ch  //向ch管道中接收数据,并复制给x,同时检查通道是否已关闭或者是否为空

当capacity=0时,channel管道是无缓冲阻塞读写,
当capacity>0时,channel管道有缓冲,是非阻塞的,直到写满capacity个元素才阻塞写入。

注意:默认情况下,channel接收和发送数据都是阻塞的,除非另一端已经准备好,这样就使得goroutine同步变得更加简单,而不需要显示的lock。

通过channel管道实现同步,和数据交互

package main
import (
	"fmt"
	"time"
)
func main() {
	//创建channel
	ch := make(chan string)
	defer fmt.Println("主协程也结束")
	go func() {
		defer fmt.Println("子协程调用完毕")
		for i := 0; i < 2; i++ {
			fmt.Println("子协程 i = ", i)
			time.Sleep(time.Second)
		}
		ch <- "我是子协程,要工作完毕"
	}()
	str := <-ch //没有数据前,阻塞
	fmt.Println("str = ", str)
}

无缓冲的channel

ch := make(chan int, 0)

package main
import (
	"fmt"
	"time"
)
func main() {
	//创建一个无缓存的channel
	ch := make(chan int, 0)

	//len(ch)缓冲区剩余数据个数, cap(ch)缓冲区大小
	fmt.Printf("len(ch) = %d, cap(ch)= %d\n", len(ch), cap(ch))
	//新建协程
	go func() {
		for i := 0; i < 10000; i++ {
			fmt.Printf("子协程:i = %d\n", i)
			ch <- i //往chan写内容
			time.Sleep(1 * time.Second)
		}
	}()
	go func() {
		for  {
			num := <-ch //读管道中内容,没有内容前,阻塞
			fmt.Println("num = ", num)
		}

	}()
	for {
	}
}

有缓冲的channel管道

ch := make(chan int, 3)

package main
import (
	"fmt"
	"time"
)
func main() {
	//创建一个有缓存的channel
	ch := make(chan int, 3)
	//len(ch)缓冲区剩余数据个数, cap(ch)缓冲区大小
	fmt.Printf("len(ch) = %d, cap(ch)= %d\n", len(ch), cap(ch))
	//新建协程
	go func() {
		for i := 0; i < 10; i++ {
			ch <- i //往chan写内容
			fmt.Printf("子协程[%d]: len(ch) = %d, cap(ch)= %d\n", i, len(ch), cap(ch))
		}
	}()
	//延时
	time.Sleep(2 * time.Second)
	for i := 0; i < 10; i++ {
		num := <-ch //读管道中内容,没有内容前,阻塞
		fmt.Println("num = ", num)
	}
}

关闭channel管道

close(ch)

package main
import (
	"fmt"
)
func main() {
	//创建一个无缓存的channel
	ch := make(chan int, 3)
	//len(ch)缓冲区剩余数据个数, cap(ch)缓冲区大小
	fmt.Printf("len(ch) = %d, cap(ch)= %d\n", len(ch), cap(ch))
	//新建协程
	go func() {
		for i := 0; i < 10000; i++ {
			fmt.Printf("子协程:i = %d\n", i)
			ch <- i //往chan写内容
			//time.Sleep(1 * time.Second)
			if i >10 {
				close(ch)
				break
			}
		}
	}()
	go func() {
		for  {
			if num, ok := <-ch; ok == true {
				fmt.Println("num = ", num)
			} else { //管道关闭
				break
			}
		}
	}()
	for {

	}
}

单向channel管道,读写分离

chan<-  表示数据进入管道,只写
<-chan 表示数据从管道出来,只读

注意:双向可转为单向,单向不可转为双向

package main
//"fmt"
func main() {
	//创建一个channel, 双向的
	ch := make(chan int)
	//双向channel能隐式转换为单向channel
	var writeCh chan<- int = ch //只能写,不能读
	var readCh <-chan int = ch  //只能读,不能写
	writeCh <- 666 //写
	//<-writeCh //err,  invalid operation: <-writeCh (receive from send-only type chan<- int)
	<-readCh //读
	//readCh <- 666 //写, err,  invalid operation: readCh <- 666 (send to receive-only type <-chan int)
	//单向无法转换为双向
	//var ch3 chan int = writeCh //cannot use writeCh (type chan<- int) as type chan int in assignment

}

管道消费者生产者模型

package main
import (
	"fmt"
)
//此通道只能写,不能读
func producer(out chan<- int) {
	for i := 0; i < 10; i++ {
		out <- i * i  //写入
	}
	close(out)  //关闭
}
//此channel只能读,不能写
func consumer(data <-chan int) {
	for num := range data {
		fmt.Println("num = ", num)
	}
}
func main() {
	//创建一个双向通道
	ch := make(chan int)
	//生产者,生产数字,写入channel
	//新开一个协程
	go producer(ch) //channel传参,引用传递
	//消费者,从channel读取内容,打印
	consumer(ch)
}

以上就是golang channel管道的详细内容,更多关于channel管道的资料请关注我们其它相关文章!

(0)

相关推荐

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

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

  • 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的用法

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

  • 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除了goroutine通信之外还有很多其他的功能,本文将实现一种基于channel的通用连接池.下面话不多说了,来一起看看详细的介绍吧. 功能 * 连接池中连接类型为interface{},使得更加通用 * 链接的最大空闲时间,超时的链接将关闭丢弃,可避免空闲时链接自动失效问题 * 使用channel处理池中的链接,高效 何为通用? 连接池的实现不依赖具体的实例,而依赖某个接口,本文的连接池选用的是io.Closer接口,只要是实现了该接口的对象都可以被池管理.

  • 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管道实现同步,和数据交互 无缓冲的channel 有缓冲的channel管道 关闭channel管道 单向channel管道,读写分离 管道消费者生产者模型 定义channel管道 定义一个channel时,也需要定义发送到管道的值类型.channel可以使用内置的make()函数来创建: var ch = make(chan int) //等价于:make(chan Type,0) var ch = make(cha

  • Go操作redis与redigo的示例解析

    目录 Go-操作redis 安装 连接 使用 设置key过期时间 批量获取mget.批量设置mset 列表操作 hash操作 Pipelining(管道) redis发布会订阅模式 事务操作 万能操作 连接redis 写入 读取 全部代码 Go-操作redis 安装 golang操作redis的客户端包有多个比如redigo.go-redis,github上Star最多的莫属redigo. github地址:https://github.com/garyburd/redigo 目前已经迁移到:h

  • Golang信号量设计实现示例详解

    目录 开篇 信号量 semaphore 扩展库实现 Acquire Release TryAcquire 总结 开篇 在我们此前的文章 Golang Mutex 原理解析 中曾提到过,Mutex 的底层结构包含了两个字段,state 和 sema: type Mutex struct { state int32 sema uint32 } state 代表互斥锁的状态,比如是否被锁定: sema 表示信号量,协程阻塞会等待该信号量,解锁的协程释放信号量从而唤醒等待信号量的协程. 这个 sema

  • golang 整合antlr语法校验解析

    目录 1. 背景 2. goland安装antlr插件 3. 编写语法校验规则 4. 语法校验 1. 背景 在项目中我们可能会遇到表达式检索的场景,例如,输入以下表达式检索,需要解析表达式并得到检索结果. ip="192.168.1.3" && (port="80" || protocol="http") 此时,我们需要对语法进行校验.解析,应当如何做呢? 下面给大家推荐一种使用语法校验工具——Antlr Antlr是一个语法分析

  • python golang中grpc 使用示例代码详解

    python 1.使用前准备,安装这三个库 pip install grpcio pip install protobuf pip install grpcio_tools 2.建立一个proto文件hello.proto // [python quickstart](https://grpc.io/docs/quickstart/python.html#run-a-grpc-application) // python -m grpc_tools.protoc --python_out=. -

  • python爬虫scrapy基于CrawlSpider类的全站数据爬取示例解析

    一.CrawlSpider类介绍 1.1 引入 使用scrapy框架进行全站数据爬取可以基于Spider类,也可以使用接下来用到的CrawlSpider类.基于Spider类的全站数据爬取之前举过栗子,感兴趣的可以康康 scrapy基于CrawlSpider类的全站数据爬取 1.2 介绍和使用 1.2.1 介绍 CrawlSpider是Spider的一个子类,因此CrawlSpider除了继承Spider的特性和功能外,还有自己特有的功能,主要用到的是 LinkExtractor()和rules

  • java理论基础Stream API终端操作示例解析

    目录 一.JavaStream管道数据处理操作 二.ForEach和ForEachOrdered 三.元素的收集collect 3.1.收集为Set 3.2.收集到List 3.3.通用的收集方式 3.4.收集到Array 3.5.收集到Map 3.6.分组收集groupingBy 四.其他常用方法 一.Java Stream管道数据处理操作 在本号之前写过的文章中,曾经给大家介绍过 Java Stream管道流是用于简化集合类元素处理的java API.在使用的过程中分为三个阶段.在开始本文之

  • Java正则表达式的语法及示例解析

    1匹配验证-验证Email是否正确 Java | 复制 public static void main(String[] args) { // 要验证的字符串 String str = "service@xsoftlab.net"; // 邮箱验证规则 String regEx = "[a-zA-Z_]{1,}[0-9]{0,}@(([a-zA-z0-9]-*){1,}\\.){1,3}[a-zA-z\\-]{1,}"; // 编译正则表达式 Pattern pat

  • Oracle PL/SQL中异常高级特性示例解析

    PL/SQL(Procedural Language/SQL,过程语言/SQL)是结合了Oracel过程语言和结构化查询语言(SQL)的一种扩展语言. 优点: (1)PL/SQL具有编程语言的特点,它能把一组SQL语句放到一个模块中,使其更具模块化种序的特点. (2)PL/SQL可以采用过程性语言控制程序的结构. (3)PL/SQL有自动处理的异常处理机制. (4)PL/SQL程序块具有更好的可移植性,可移植到另一个Oracle数据库中. (5)PL/SQL程序减少了网络的交互,有助于提高程序性

  • java eclipse 中文件的上传和下载示例解析

    文件的上传与下载(一) 在实现文件上传和下载之前我们需要做一些准备工作,在Apache官网去下载文件上传下载的两个组件,下载链接这里给出:common-fileupload组件下载:http://commons.apache.org/proper/commons-fileupload/ common-io组件下载:http://commons.apache.org/proper/commons-io/根据自己需求下载对应版本 一.创建工程 将所需要的两个开发包导入到工程项目中如图: 二.代码编写

随机推荐