Go语言 Channel

基本介绍

Channel 是 Go 中的一个核心类型,可以把它看成一个管道。
利用通道我们可以在多个 goroutine 之间传递数据。
如果说 Goroutine 是 Go 程序并发的执行体,Channel 就是它们之间的连接。
Channel 是可以让一个 Goroutine 发送特定值到另一个 Goroutine 的通信机制。
Channel 像一个传送带或者队列,总是遵循先入先出(First In First Out)的规则,保证收发数据的顺序。

基本使用

声明

  1. 声明 channel: var 变量 chan 元素类型
  2. 声明的通道后需要使用 make 函数初始化之后才能使用
	var ch1 chan int   // 声明一个传递整型的通道
	var ch2 chan bool  // 声明一个传递布尔型的通道
	var ch3 chan string // 声明一个传递字符串的通道     
	ch1 := make(chan int) // 直接初始化一个无缓冲通道
	ch2 := make(chan int,2) // 初始化一个带缓冲的通道

操作

  1. 通道有发送(send)、接收(receive)和关闭(close)三种操作。
  2. 发送和接收都使用 <- 符号。

发送

  1. 使用 <- 符号放到通道变量右边,就可以把值发送到创建的通道中,看起来就像值流向通道中。
	ch1 := make(chan int ,1)
	ch1 <-1

接收

  1. 使用 <- 符号放到通道变量左边,就可以从通道中接收一个值,看起来就像通道中流出一个值到变量中。
	ch1 := make(chan int ,1)
	ch1 <-1
	result := <- ch1
	fmt.Println(result) // 1

关闭

使用 close 函数可以把通道关闭

	close(ch1)

关闭通道特点

虽然关闭通道看起来很简单,但是在实际场景中需要特别注意通道的关闭,如果不能正确通道,会引起一些意想不到的错误。
关闭后的通道有以下特点:

  1. 对一个关闭的通道再发送值就会导致 panic (demo1)。
  2. 关闭一个已经关闭的通道会导致 panic (demo2)
  3. 对一个关闭的通道进行接收会一直获取值直到通道为空 (demo3)。
  4. 对一个关闭的并且没有值的通道执行接收操作会得到对应类型的零值 (demo4)。

demo1

	func demo1(){
		ch1 := make(chan int ,1)
		close(ch1)
		ch1 <- 1  // panic: send on closed channel
	}

demo2

	func demo2(){
		ch1 := make(chan int ,1)
		close(ch1)
		close(ch1) // panic: close of closed channel
	}

demo3

	func demo3(){
		ch1 := make(chan int ,3)
		for i:=0;i<3;i++{
			ch1 <- i
		}
		close(ch1)
		for v := range ch1{
			fmt.Println(v)
		}
	}
  1. 如果这里不关闭 ch1 这个通道,下面的 for range 会一直去遍历 通道
  2. 没有值的话就会造成阻塞,在主协程里造成阻塞的话,就会造成死锁报以下致命错误
  3. 所以在使用 for range 去遍历通道的时候要注意关闭,或者在子协程里去这样使用。
	fatal error: all goroutines are asleep - deadlock!

demo4

	func demo4(){
		ch1 := make(chan int ,1)
		ch1 <-1
		close(ch1)
		fmt.Println(<-ch1)  //1
		fmt.Println(<-ch1) // 0
		result , ok := <- ch1
		fmt.Println(result) // 0
		fmt.Println(ok) //false
	}
  1. 通道关闭了是可以继续接收值的
  2. 如果有值则接收值,没有值则返回通道类型的零值
  3. 如果想知道通道是否关闭,可以接收第二个值,通过第二个值来判断通道是否关闭

无缓冲通道

通道有两种,无缓冲通道和带缓冲通道,先看下无缓冲通道。
无缓冲通道,发送者和接受者都要存在,有一方不存在会导致阻塞。
所以说无缓冲的通道又被称为阻塞的通道。

	ch := make(chan int)
	ch <- 10
	fmt.Println("发送成功")

以上代码会报错

	fatal error: all goroutines are asleep - deadlock!
	goroutine 1 [chan send]:

为什么会报错呢?
我们使用 ch := make(chan int)创建的是无缓冲的通道。
无缓冲的通道只有在有接收方接收值的时候才能发送值,但是在一个协程里执行到发送方或者接收方的时候就会阻塞,所以需要在两个协程间接收和发送。

代码调整

	func demo5(){
		ch := make(chan int)
		go func() {
			result := <- ch
			fmt.Println("接收成功",result)
		}()
		ch <- 10
		fmt.Println("发送成功")
	}
	func demo6(){
		ch := make(chan int)
		go func() {
			ch <- 10
			fmt.Println("发送成功")
		}()
		result := <- ch
		fmt.Println("接收成功",result)
	}

上面两种形式都可以,只要不要造成主协程阻塞就可以,主协程如果阻塞了就会报致命错误死锁。

缓冲通道

解决无缓冲通道(阻塞)死锁的问题,就是使用有缓冲的通道。通过缓存的使用,可以尽量避免阻塞,提高应用的性能。
带缓冲的通道允许发送端的数据发送和接收端的数据获取处于异步状态,就是说发送端发送的数据可以放在缓冲区里面,可以等待接收端去获取数据,而不是立刻需要接收端去获取数据。
我们使用 make 函数在初始化的时候为其指定通道的容量(缓冲大小):
只要通道的容量大于零,那么该通道就是有缓冲的通道,通道的容量表示通道中能存放元素的数量。
我们可以使用内置的 len 函数获取通道内元素的数量,使用 cap 函数获取通道的容量。

	func demo7(){
		ch := make(chan int ,1)  // 创建一个容量为 1 的有缓冲区的通道
		ch <- 10
		fmt.Println("发送成功")
		result := <- ch
		fmt.Println("接收成功",result)
	}

这个例子中,创建了带1个缓冲的通道,所以往里面写值的时候没有造成阻塞。

	ch := make(chan int ,1)  // 创建一个容量为 1 的有缓冲区的通道
	ch <- 10 
	ch <- 10
	fmt.Println("发送成功")

这个例子中,第一次写值的时候可以,第二次写值的时候就会阻塞然后报死锁错误。

扇入和扇出

扇出/扇入模式是并发编程中常用的设计模式,特别是在 Go 语言中。它包括两个阶段:

  1. 扇出阶段,在这个阶段,单个 goroutine 将任务广播给多个工作 goroutine;
  2. 扇入阶段,在这个阶段,这些工作 goroutine 的结果被聚合到一个单一的通道中。

FAN - OUT 扇出

	func demo9() {
		taskChan := make(chan int, 10)
		quitChan := make(chan int,3)
	
		go func() {
			for i := 1; i <= 10; i++ {
				taskChan <- i
			}
			close(taskChan)
		}()
	
		go func() {
			for v := range taskChan{
				fmt.Println("work 1 处理任务:",v)
			}
			quitChan <-1
		}()
	
		go func() {
			for v := range taskChan{
				fmt.Println("work 2 处理任务:",v)
			}
			quitChan <-1
		}()
	
		go func() {
			for v := range taskChan{
				fmt.Println("work 3 处理任务:",v)
			}
			quitChan <-1
		}()
	
		<- quitChan
		<- quitChan
		<- quitChan
		fmt.Println("over")
	}

输出结果

	work 3 处理任务: 2
	work 3 处理任务: 4
	work 3 处理任务: 5
	work 3 处理任务: 6
	work 3 处理任务: 7
	work 3 处理任务: 8
	work 3 处理任务: 9
	work 3 处理任务: 10
	work 1 处理任务: 1
	work 2 处理任务: 3
	over

FAN - IN 扇入

func demo10(){
	taskChan := make(chan int, 10)
	quitChan := make(chan int,3)
	overChan := make(chan int)

	go func() {
		for i := 1; i <= 5; i++ {
			taskChan <- i
		}
		quitChan <-1
	}()

	go func() {
		for i := 5; i <= 10; i++ {
			taskChan <- i
		}
		quitChan <-1
	}()

	go func() {
		for v := range taskChan{
			fmt.Println("work  处理任务:",v)
		}
		fmt.Println("任务全部处理了")
		overChan <- 1
	}()

	<-quitChan
	<-quitChan
	close(taskChan)
	<-overChan
	fmt.Println("over")
}
	work  处理任务: 5
	work  处理任务: 6
	work  处理任务: 7
	work  处理任务: 8
	work  处理任务: 9
	work  处理任务: 10
	work  处理任务: 1
	work  处理任务: 2
	work  处理任务: 3
	work  处理任务: 4
	work  处理任务: 5
	任务全部处理了
	over

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/576720.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Feign功能详解、使用步骤、代码案例

简介&#xff1a;Feign是Netflix开发的声明式&#xff0c;模板化的HTTP客户端&#xff0c;简化了HTTP的远程服务的开发。Feign是在RestTemplate和Ribbon的基础上进一步封装&#xff0c;使用RestTemplate实现Http调用&#xff0c;使用Ribbon实现负载均衡。我们可以看成 Feign R…

经典的免费wordpress模板

这款经典的免费WordPress模板以鲜艳的红色为主调&#xff0c;充满了活力与热情。设计简洁而现代&#xff0c;适合各种类型的项目网站。模板采用响应式设计&#xff0c;确保在不同设备和屏幕尺寸上都能呈现出完美的视觉效果。 红色象征着激情、活力和自信&#xff0c;这款模板…

ubuntu子系统密码忘记了,怎么办?

&#x1f3c6;本文收录于「Bug调优」专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&&…

18种WEB常见漏洞:揭秘网络安全的薄弱点

输入验证漏洞: 认证和会话管理漏洞: 安全配置错误: 其他漏洞: 防范措施: Web 应用程序是现代互联网的核心&#xff0c;但它们也容易受到各种安全漏洞的影响。了解常见的 Web 漏洞类型&#xff0c;对于开发人员、安全测试人员和普通用户都至关重要。以下将介绍 18 种常见的 …

HttpClient工具类编写

HttpClient 介绍 HttpClient是Apache Jakarta Common下的一个子项目&#xff0c;它提供了一个高效的、最新的、功能丰富的支持HTTP协议的客户端编程工具包。它支持HTTP协议最新的版本和建议&#xff0c;并实现了Http1.0和Http1.1协议。 HttpClient具有可扩展的面向对象的结构…

电脑壁纸怎么设置?简单3步,让你的电脑桌面变得更合心意

电脑壁纸是我们每天在电脑上工作和娱乐时不可或缺的一部分。一张精美的电脑壁纸&#xff0c;既能提升我们的工作效率&#xff0c;也能为我们带来愉悦的心情。无论是静谧的自然风光、抽象的艺术设计&#xff0c;还是心动的明星照片&#xff0c;都可以在电脑壁纸的世界里找到自己…

HF区块链链码基础

链码生命周期 一 . 链码准备 准备文件 . 在测试目录下创建chaincode,拷贝测试链码进 chaincode目录,拷贝 set-env.sh 脚本进 scripts 目录 二. 打包链码 打包测试链码 export FABRIC_CFG_PATH${PWD}/config peer lifecycle chaincode package ./chaincode/chaincode_basic.…

Springboot 中RedisTemplate使用scan来获取所有的key底层做了哪些事情

直接上代码&#xff0c;围绕着代码来讨论 redisTemplate.execute((RedisCallback<Object>) (connection) -> {Cursor<byte[]> scan connection.scan(ScanOptions.scanOptions().count(2).match("*").build());scan.forEachRemaining((bytes) -> {…

TypeScript 中 interface 和 type 的使用#记录

一、interface&#xff1a;接口 interface A{label: string; }const aa ((aObj: A) > {console.log(aObj.label);//123return aObj.label; })aa({label: 123}) 1、可选属性 interface A{label: string;age?: number; } 2、只读属性 interface A{label: string;age?:…

【网络安全】安全事件管理处置 — windows应急响应

专栏文章索引&#xff1a;网络安全 有问题可私聊&#xff1a;QQ&#xff1a;3375119339 目录 一、账户排查 二、windows网络排查 三、进程排查 四、windows注册表排查 五、内存分析 总结 一、账户排查 账户排查主要包含以下几个维度 登录服务器的途径弱口令可疑账号 新增…

019基于JavaWeb的在线音乐系统(含论文)

019基于JavaWeb的在线音乐系统&#xff08;含论文&#xff09; 开发环境&#xff1a; Jdk7(8)Tomcat7(8)MysqlIntelliJ IDEA(Eclipse) 数据库&#xff1a; MySQL 技术&#xff1a; JavaServletJqueryJavaScriptAjaxJSPBootstrap 适用于&#xff1a; 课程设计&#xff0c;毕…

Web-SpringBootWen

创建项目 后面因为报错&#xff0c;所以我把jdk修改成22&#xff0c;仅供参考。 定义类&#xff0c;创建方法 package com.start.springbootstart.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotati…

易基因:Nat Commun:RRBS测序揭示小鼠衰老过程中的DNA甲基化变化轨迹|研究速递

大家好&#xff0c;这里是专注表观组学十余年&#xff0c;领跑多组学科研服务的易基因。 DNA甲基化数据可以生成非常精确的年龄预测器&#xff0c;但关于这一关键表观遗传生物标志物在生命周期中的动态变化知之甚少。关于衰老不连续方面的研究仍处于起步阶段&#xff0c;关键的…

冯唐成事心法笔记 —— 知人

系列文章目录 冯唐成事心法笔记 —— 知己 冯唐成事心法笔记 —— 知人 冯唐成事心法笔记 —— 知世 冯唐成事心法笔记 —— 知智慧 文章目录 系列文章目录PART 2 知人 人人都该懂战略人人都该懂战略第一&#xff0c;什么是战略第二&#xff0c;为什么要做战略第三&#xff0…

文本溢出 右侧对齐 左侧显示省略号

要想 把 “这是一段很长的文本&#xff0c;我们只想显示省略号前面的部分内容" 展示成”…只想显示省略号前面的部分内容“ 代码如下 <div class"ellipsis-start">这是一段很长的文本&#xff0c;我们只想显示省略号前面的部分内容</div>.ellips…

力扣118. 杨辉三角

Problem: 118. 杨辉三角 文章目录 题目描述思路复杂度Code 题目描述 思路 1.初始化状态&#xff1a;将创建的二维数组dp的第一列和主对角线上元素设为1&#xff1b; 2.状态的转移&#xff1a;从第一行、列起始&#xff0c;dp[i][j] dp[i - 1][j - 1] dp[i - 1][j] 复杂度 时…

vue3第二十五节(h()函数的应用)

1、前言&#xff1a; 为什么vue 中已经有 template 模板语法&#xff0c;以及JSX了&#xff0c;还要使用 h()渲染函数&#xff1b; vue 中选择默认使用template 静态模板分析&#xff0c;有利于DMO性能的提升&#xff0c;而且更接近真实的HTML&#xff0c;便于开发设计人员理…

Java之复制图片

从文件夹中复制图片 从这个文件夹&#xff1a; 复制到这个空的文件夹&#xff1a; 代码如下&#xff1a; import java.io.*; import java.util.Scanner;/*** 普通文件的复制*/public class TestDome10 {public static void main(String[] args) {// 输入两个路径// 从哪里(源路…

ssm智能停车场管理系统

视频演示效果: SSMvue智能停车场 摘 要 本论文主要论述了如何使用JAVA语言开发一个智能停车场管理系统&#xff0c;本系统将严格按照软件开发流程进行各个阶段的工作&#xff0c;采用B/S架构&#xff0c;面向对象编程思想进行项目开发。在引言中&#xff0c;作者将论述智能停车…

2024多用户商城系统哪家产品好

在当今激烈的电商竞争中&#xff0c;搭建一个功能强大、性能稳定的多用户商城系统至关重要。针对这一需求&#xff0c;以下是我为您推荐的五款优秀多用户商城系统&#xff0c;它们在功能、定制性、安全性和用户体验方面均表现出色&#xff0c;为您的电商平台搭建提供了可靠的解…
最新文章