[Golang] Channel

news2024/9/29 20:22:43

[Golang] Channel

文章目录

  • [Golang] Channel
    • 什么是Channel
    • channel的初始化
    • channel的操作
    • 双向channel和单向channel
    • 为什么有channel
    • 有缓冲channel和无缓冲channle
    • channel做一把锁

从之前我们知道go关键字可以开启一个Goroutine,但是Goroutine之间的通信还需要另一个条件:channel

什么是Channel

官方定义:Channel are typed conduit through which you can send and receive values with the channel operator.

channel是一个可以收发数据的管道。

channel的初始化

var channel_name chan channel_type
var channel_name [size]chan channel_type//声明一个容量为size的channel

例如:

var ch1 chan int
var ch2 [1]chan int

但是声明后的channel,我们没有进行初始化为其分配空间,其值为nil,我们还需要使用make函数来对其初始化,之后才可以在程序中使用该管道。

channel_name = make(chan channel_type)
channel_name = make(chan channel_type, size)

例如:

ch1 := make(chan int)
ch2 := make(chan int, 1)//一个容量为size的channel

channel的操作

发送数据:

ch := make(chan int)	// 创建管道
ch <- 1					// 向管道发送数据
v := <-ch				// 从管道读取数据,并存储的变量v
close(ch)				// 关闭管道

注意:用完管道后,我们需要关闭管道close(ch),避免程序一直等待以及资源的浪费。但是关闭的管道仍然能读取数据,如果管道中还有数据,那就可以读到实际的值;如果管道中没有数据,此时读取的值就是该类型的零值,不会阻塞等待数据。

比如,例:

package main

import (
	"fmt"
	"time"
)

func main() {
	ch := make(chan int, 5)
	ch <- 1
	close(ch)
	go func() {
		for i := 0; i < 5; i++ {
			v := <-ch
			fmt.Println(v)
		}
	}()
	time.Sleep(2 * time.Second)
}

执行结果:

image-20240913234519220

创建一个缓存为5的int类型管道,向管道里写入一个1之后关闭管道。开启一个Goroutine从管道中读取数据,读5次,我们可以看到从第二次开始,读到的数据一直是0。

但是如果我们想要向管道中写入0呢?

一般采用:

1.判断读取:

package main

import (
	"fmt"
	"time"
)

func main() {
	ch := make(chan int, 5)
	ch <- 1
	close(ch)
	go func() {
		for i := 0; i < 5; i++ {
			v, ok := <-ch 						// 判断式读取
			if ok {
				fmt.Println("数据读完了", v)
			} else {
				fmt.Println("数据没读完", v)
			}
		}
	}()
	time.Sleep(2 * time.Second)
}

执行结果:

image-20240913234937999

我们在读取数据时,加上了一个ok进行判断。ok为true时,读取的是正常值;ok为false,读取的是零值。

2.for range 读取

有时,我们的读取是不知道次数的,只是在channel中进行读取,有数据我们就读,直到管道关闭。

此时可以使用for range 读取管道中的数据

package main

import (
	"fmt"
	"time"
)

func main() {
	ch := make(chan int, 5)
	ch <- 1
	ch <- 2
	ch <- 3
	close(ch)
	go func() {
		for i := 0; i < 5; i++ {
			for v := range ch {
				fmt.Println(v)
			}
		}
	}()
	time.Sleep(2 * time.Second)
}

执行结果:

image-20240913235317638

我们向管道中只写入了1,2,3,三个数据,之后就关闭了管道。Goroutine中也只能读到三个数据,然后管道被关闭了,Goroutine的for range循环也就退出了。

双向channel和单向channel

channel根据其功能又能分为双向channel和单向channel,双向channel既可以发送数据又可以接收数据,单向channel要么是发送数据,要么是接收数据。

单向读channel

var ch = make(chan int)
type ReadChannel = <-chan int	// 给 <-chan int取个别名
var rec ReadChannel = ch

单向写channel

var ch = make(chan int)
type SendChannel = chan<- int
var sec SendChannel = ch

读channel与写channel在定义时只是<-的位置不同,读在chan关键字前,写在chan关键字后。

使用示例:

package main

import (
	"fmt"
	"time"
)

type ReadChannel = <-chan int
type SendChannel = chan<- int

func main() {
	var ch = make(chan int)
	defer close(ch)
	go func() {
		var rec ReadChannel = ch
		v := <-rec
		fmt.Println(v)
	}()
	go func() {
		var sec SendChannel = ch
		sec <- 100
	}()

	time.Sleep(2 * time.Second)
}

执行结果:

image-20240914000632202

创建一个读channel,一个写channel,向写channel中写入100,从读channel中读取数据。

为什么有channel

Golang中有个重要的思想:不以共享内存来通信,以通信来共享内存,channel就是其特点。

也就是说,协程之间可以利用channel来传递数据,以下例子可以看出父子协程是如何通过channel通信的:

package main

import (
	"fmt"
	"time"
)

func sum(nums []int, ch chan int) {
	cnt := 0
	for _, v := range nums {
		cnt += v
	}
	ch <- cnt
}

func main() {
	var ch = make(chan int)
	defer close(ch)
	nums := []int{-5, 4, -3, 2, -1} // 和为-3
	go func() {
		sum(nums[:len(nums)/2], ch)
	}()
	go sum(nums[len(nums)/2:], ch)
	m, n := <-ch, <-ch
	fmt.Println(m, n, m+n)

	time.Sleep(2 * time.Second)
}

执行结果:

image-20240914001709564

有缓冲channel和无缓冲channle

之前初始化时,我们已经说明了channel分为有缓冲和无缓冲两种。

为了协程安全,有缓冲channel和无缓冲channle的内部都有一把锁来控制并发访问。

同时,channel底层一定有一个队列来存储数据。

无缓冲channel可以理解为同步模式,即写入一个,如果消费者不消费,写入就会阻塞

有缓冲channel可以理解为异步模式,即写入消息后,即使没有被消费,只要队列没有满,就可以继续写入。

image-20240914002245442

此时如果,channel满了,异步就会退化为同步,发送还是会阻塞。如果一个channel长期处于满队列状态,就没必要使用有缓冲channel了,直接有无缓冲即可。

所以大部分情况,有缓冲的channel一般用来做异步操作。

  • 无缓冲channel:适合用于严格同步的场景,比如两个Goroutine之间进行同步,要严格确保操作顺序。

例如,两个协程循环打印A、B

package main

import (
	"fmt"
	"sync"
	"time"
)

func main() {
	var wg sync.WaitGroup
	wg.Add(2)

	var Ach = make(chan int)
	var Bch = make(chan int)
	defer close(Ach)
	defer close(Bch)

	go PrintA(&wg, Ach, Bch)
	go PrintB(&wg, Ach, Bch)

	Ach <- 1 // 从A启动

	wg.Wait()
}

func PrintA(wg *sync.WaitGroup, Ach chan int, Bch chan int) {
	defer wg.Done()
	for {
		<-Ach
		fmt.Println("A")
		time.Sleep(time.Second)
		Bch <- 1 // 通知打印B
	}
}

func PrintB(wg *sync.WaitGroup, Ach chan int, Bch chan int) {
	defer wg.Done()
	for {
		<-Bch
		fmt.Println("B")
		time.Sleep(time.Second)
		Ach <- 1 // 通知打印A
	}
}
  • 有缓冲channel:适合一定程度的异步处理的场景,比如提高吞吐量,减少Goroutine之间的阻塞。

channel做一把锁

因为缓冲队列满了之后,再往channel中写数据就会被阻塞,所以我们可以把channel当一把锁来使用

package main

import (
	"fmt"
	"time"
)

func main() {
	ch := make(chan bool, 1)

	var sum int
	for i := 0; i < 1000; i++ {
		go add(ch, &sum)
	}
	time.Sleep(2 * time.Second)
	fmt.Println("sum = ", sum)
}

func add(ch chan bool, sum *int) {
	ch <- true
	*sum = *sum + 1
	<-ch
}

执行结果:

image-20240914004020661

如果不用锁,循环次数一多就会出现并发问题。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Recyclerview实现滑动居中缩放菜单

最近项目中需要的一个滑动菜单效果:要求当前居中选项放大、滑动时有缩放效果、点击两边的选项滑动到屏幕中央、停止滑动选项停留在屏幕中间(类似viewPager的效果),为了直观,先上最终实现效果图: 大体思路: Recyclerview item头尾添加空数据,让第一个和最后一个item也能…

计算机组成原理(第二次笔记)

各种码 真值 (书写用)&#xff1a; 将用“”、“-” 表示正负的二进制数称为真值 机器不能识别书写格式&#xff0c;故用“0/1”表示“/-”符号。 机器码 (机器内部使用)&#xff1a; 将符号和数值一起编码表示的二进制数称为机器码。 常用机器码&#xff1a;原码、 反码、 补…

Linux网络编程 --- 高级IO

前言 IO Input&&Output read && write 1、在应用层read && write的时候&#xff0c;本质把数据从用户层写给OS --- 本质就是拷贝函数 2、IO 等待 拷贝。 等的是&#xff1a;要进行拷贝&#xff0c;必须先判断读写事件成立。读写事件缓冲区空间满…

Kafka+PostgreSql,构建一个总线服务

之前开发的系统&#xff0c;用到了RabbitMQ和SQL Server作为总线服务的传输层和存储层&#xff0c;最近一直在看Kafka和PostgreSql相关的知识&#xff0c;想着是不是可以把服务总线的技术栈切换到这个上面。今天花了点时间试了试&#xff0c;过程还是比较顺利的&#xff0c;后续…

破解AI生成检测:如何用ChatGPT降低论文的AIGC率

学境思源&#xff0c;一键生成论文初稿&#xff1a; AcademicIdeas - 学境思源AI论文写作 降低论文的“AIGC率”是个挑战&#xff0c;但有一些策略可以尝试。使用ChatGPT逐步调整和改进内容&#xff0c;使其更加自然和原创&#xff0c;降低AI检测工具识别出高“AIGC率”的概率…

专访阿里云:AI 时代服务器操作系统洗牌在即,生态合作重构未来

编者按&#xff1a;近日&#xff0c;2024 龙蜥操作系统大会已于北京圆满举办。大会期间&#xff0c;CSDN 采访了阿里云基础软件部资深技术总监、龙蜥社区技术委员会主席杨勇&#xff0c;前瞻性宏观解读面向 AI 智算时代&#xff0c;服务器操作系统面临的挑战与机遇。以下为采访…

云曦2024秋考核

真正的hacker 进去以后一眼就能看出来&#xff0c;是ThinkphpV5漏洞&#xff0c;只是版本不能确定&#xff0c;一开始考核的时候是&#xff0c;抓包看了php的版本&#xff0c;是7.23&#xff0c;是手注了几个尝试出来的&#xff08;后面才发现报错信息里面就有&#xff09;。漏…

记录word转xml文件踩坑

word文件另存为xml文件后&#xff0c;xml文件乱码 解决方法&#xff1a; 1.用word打开.docx文件 2.另存为xml文件 3.点击工具 -> Web选项 -> 编码&#xff0c;选择UTF-8 4.点击确定 5.使用notpad打开xml文件 6.使用xml tool进行xml格式化即可。

【免费资料推荐】数据资产管理实践白皮书(6.0版)

荐言&#xff1a;随着数字经济的快速发展&#xff0c;数据已成为企业最重要的资产之一。为有效管理和利用数据资产&#xff0c;各行业纷纷推出数据管理框架和标准。数据资产管理实践白皮书&#xff08;6.0版&#xff09;由中国信息通信研究院联合相关企业共同编写&#xff0c;是…

利士策分享,细品礼仪之美:在日常中优雅相处的艺术

利士策分享&#xff0c;细品礼仪之美&#xff1a;在日常中优雅相处的艺术 在当今这个快节奏、高压力的社会里&#xff0c;人与人之间的交往似乎被简化成了快餐式的信息交流。 然而&#xff0c;根植于文化深处的礼仪之花&#xff0c;依然是促进社会和谐、深化人际关系的宝贵财富…

python使用Pandas读取excel的行列内容

我的Excel文件名称是“测试.xlsx” 首先读取excle的文件内容 import pandas as pd dfpd.read_excel(测试.xlsx) #这个会直接默认读取到这个Excel的第一个sheet print(df)可以看看输出的是什么&#xff1a; 2. df.loc[0]&#xff0c;表示读取Excel的第一行&#xff08;这里…

docker容器中的内存占用高的问题分析

文章目录 问题描述原因分析分析1分析2验证猜想 结论和经验 问题描述 运维新增对某服务的监控后发现&#xff1a;内存不断上涨的现象。进一步确认&#xff0c;是因为有多个导出日志操作导致的内存上涨问题。 进一步的测试得出的结果是&#xff1a;容器刚启动是占用内存约为50M…

白话:大型语言模型中的幻觉(Hallucinations)

大型语言模型&#xff08;LLM&#xff09;可是自然语言处理和人工智能的一大步。它们能做的事情可多了&#xff0c;比如生成听起来挺靠谱的文本&#xff0c;翻译语言&#xff0c;总结文档&#xff0c;甚至写诗。但你知道吗&#xff0c;这些模型有时候会出现 “幻觉&#xff08;…

音视频开发常见的开源项目

FFmpeg 地址&#xff1a;https://ffmpeg.org/介绍&#xff1a;FFmpeg 是一个非常强大的开源多媒体框架&#xff0c;它可以用来处理视频和音频文件。它支持多种格式的转换、编码、解码、转码、流处理等。FFmpeg 包括了 libavformat、libavcodec、libavutil、libswscale、libpos…

Matlab求解微分方程(解析解与数值解)

matlab求解微分方程解析解和数值解 Matlab求微分方程解析解例题1例题2例题3 Matlab求微分方程数值解一阶微分方程例题一例题二 高阶微分方程例题 Matlab求微分方程解析解 dsolve(eqns,conds,options) eqns:微分方程&#xff08;组&#xff09;、conds&#xff1a;初值条件、opt…

萌宠宜家商城系统

摘 要 随着现在经济的不断发展和信息技术性日益完善和优化&#xff0c;传统式数据信息的管理升级成手机软件存放、梳理和数据信息集中统一处理的管理方式。本萌宠物宜家商城系统软件起源于这个环境中&#xff0c;能够帮助管理者在短期内进行庞大数据信息。使用这个专业软件能够…

【开源免费】基于SpringBoot+Vue.JS购物商城网站(JAVA毕业设计)

本文项目编号 T 032 &#xff0c;文末自助获取源码 \color{red}{T032&#xff0c;文末自助获取源码} T032&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析 六、核心代码6.1 查…

文字识别多功能工具箱 | eSearch v13.1.6

eSearch v13.1.6 是一款开源的截屏识屏搜索工具&#xff0c;它提供了丰富的功能&#xff0c;包括截屏、OCR识别、搜索翻译、贴图、以图搜图和录屏等一体化实用工具。该软件基于 Electron 框架开发&#xff0c;适用于 Linux、Windows 和 macOS 平台。 软件的主要特点和功能包括…

Lua发邮件:实现自动化邮件发送教程指南!

Lua发邮件高级技巧有哪些&#xff1f;如何利用Lua发送电子邮件&#xff1f; 自动化邮件发送是一个非常实用的功能&#xff0c;广泛应用于各种场景&#xff0c;如通知、提醒、报告生成等。Lua作为一种轻量级脚本语言&#xff0c;因其简洁和高效而受到广泛欢迎。AokSend将详细介…

金钥匙系列:Kubernetes (K8s) 服务集群技术栈学习路线

维护Kubernetes (K8s) 服务集群是一个复杂且多层次的技术任务&#xff0c;涉及容器化技术、集群管理、网络、安全、监控等多个领域。为了成为一名优秀的K8s集群维护工程师&#xff0c;技术栈需要广泛且深入。本文将为你详细介绍从零开始到深入掌握K8s集群维护的职业技术栈学习路…