go语言中channel类型

目录

什么是channel

为什么要有channel

channel操作使用

初始化:

操作:

单向channel

双向channel,可读可写:

close下什么场景会出现panic

总结


什么是channel

Channels are a typed conduit through which you can send and receive values with the channel operator, <-.

        channel是go语言的核心类型之一,翻译为中文是“通道,管道”,为了实现协程间的同步与通信。遵循FIFO(先进先出)的队列,保证线程安全。

为什么要有channel

“不要用共享内存来通信,而是使用通信来共享内存” -- go语言并发哲学

        任何一种程序语言要实现并发能力,就要做好多线程之间的协调工作,让彼此知道对方状态,获取对方的信息,完成预定任务。大多数的编程语言的并发编程模型是基于线程和内存同步访问控制,go语言的并发编程的模型则用 goroutine 和 channel 来实现。channel是goroutine之间架了一条管道,在管道里传输数据,实现goroutine间的通信来协调工作(当然goroutine实现通信不止channel一种,还有 go语言中协程实现通信的三种方式 context\sync.cond\channel)。

        在go语言中,CSP(Communicating Sequential Processes)模型是go语言并发编程哲学的实现(三种线程模型与CSP实现),goroutine与channel是CSP上层实现的两大基石。

        channel的底层实现保证了协程操作安全:在任何同一时间内,channel中的一个数据只允许一个协程访问,不存在数据竞争。

channel操作使用

初始化

channel是引用类型,有带缓冲channel和无缓冲channel,未初始化的channel值是nil。通过内建函数make (仅对map\slice\channel初始化)分配内存并初始化。

操作

channel只有三种操作方式Send、Receive、close

通过操作符 <- 实现发送或读取数据中文社区更愿意把Send和接收从通信操作符号看chan <- 是发送数据到chan,<- chan是接收chan中数据这是从通信角度理解从读写角度理解我更愿意翻译为chan <- 为写入数据到chan,<-chan为从chan读取数据出来)。数据为go中任意类型

close为关闭chan:close(chan)

虽然go语言采自动垃圾回收机制来管理内存,但go的垃圾回收器不会主动回收运行中的channel, 主动关闭channel为了防止内存泄露。

单向channel

单向channel分为write-only,read-only channel,主要作用有限制通信方向、减少竞态条件、提高代码可读性。

        限制通信方向:使用只写通道可以在某些情况下限制通信的方向,确保特定的协程只能发送数据到通道,而不会在不适当的地方进行接收操作。这有助于清晰地定义协程之间的职责和交互。

        减少竞态条件:当只有一个协程负责向通道发送数据,而其他协程只负责接收时,可以减少竞态条件的出现。这有助于避免数据竞争和复杂的同步问题。

        提高代码可读性:通过使用只写通道,你可以在代码中清楚地表达协程的作用。这有助于其他开发人员更容易地理解代码并阅读文档。

unc worker(id int, jobs <-chan int, results chan<- int) {for job := range jobs {fmt.Printf("Worker %d started job %d\n", id, job)time.Sleep(time.Millisecond)fmt.Printf("Worker %d finished job %d\n", id, job)results <- job * 2}
}func main() {numJobs := 5jobs := make(chan int, numJobs)results := make(chan int, numJobs)// 启动3个工作协程for i := 1; i <= 3; i++ {go worker(i, jobs, results)}// 向通道发送任务for j := 1; j <= numJobs; j++ {jobs <- j}close(jobs)// 收集结果for r := 1; r <= numJobs; r++ {result := <-resultsfmt.Println("Result:", result)}
}

在这个示例中,我们使用只写通道 chan<- 来传递任务给工作协程,工作协程的<- chan只负责从通道中接收任务。这种模式将任务分发和执行解耦,增加了代码的可读性和可维护性。

总之,单向channel在go语言中用于限制通道的使用方向,有助于提高代码的可读性、降低竞态条件和减少复杂性。

双向channel,可读可写:

基本通道使用:创建一个通道,发送数据到通道,然后从通道接收数据

func base() {ch := make(chan int) // 创建一个通道go func() {ch <- 42 // 发送数据到通道}()value := <-ch                   // 从通道接收数据fmt.Println("Received:", value) // Received: 42
}

使用缓冲通道:创建带有缓冲区的通道,可以存储多个数据,然后使用循环向通道发送和接收数据。

func cacheChan() {ch := make(chan int, 2) // 创建一个容量为2的缓冲通道ch <- 1ch <- 2value1 := <-chvalue2 := <-chfmt.Println("Received:", value1, value2) // Received: 1 2
}

协程池: 使用通道来实现一个简单的协程池,从通道中获取任务并分发给协程进行处理。

func worker(id int, jobs <-chan int, results chan<- int) {for job := range jobs {fmt.Printf("Worker %d started job %d\n", id, job)time.Sleep(time.Millisecond)fmt.Printf("Worker %d finished job %d\n", id, job)results <- job * 2}
}func goroutinePool() {numJobs := 5numWorkers := 3jobs := make(chan int, numJobs)results := make(chan int, numJobs)for i := 1; i <= numWorkers; i++ {go worker(i, jobs, results)}for j := 1; j <= numJobs; j++ {jobs <- j}close(jobs)var wg sync.WaitGroupwg.Add(numJobs)go func() {wg.Wait()close(results)}()for r := range results {fmt.Println("Result:", r)wg.Done()}
}

取消协程: 使用通道来实现协程的取消,通过发送信号告知协程停止工作。

func worker(cancel <-chan struct{}) {for {select {case <-cancel:fmt.Println("Worker canceled")returndefault:fmt.Println("Working...")time.Sleep(time.Second)}}
}func cancelRoutine() {cancel := make(chan struct{})go worker(cancel)time.Sleep(3 * time.Second)fmt.Println("Canceling worker...")close(cancel)time.Sleep(1 * time.Second)
}

close下什么场景会出现panic

在使用channel时,为了获得良好的协程同步与通信结果,在一些场景下会导致程序panic,

如下为读写与channel状态对协程的影响表:

调用close关闭channel时,未初始化时关闭、重复关闭、关闭后发送、发送时关闭,在这四种情况下会出现panic:

        未初始化就关闭

func main() {var ch chan intclose(ch) // panic: close of nil channel
}

        重复关闭

func main() {ch := make(chan int)close(ch)close(ch) // panic: close of closed channel
}

        关闭后发送

func main() {wg := sync.WaitGroup{}wg.Add(1)ch := make(chan int)close(ch)go func() {defer wg.Done()ch <- 1 // panic: send on closed channel}()<-chwg.Wait()
}

        发送后关闭

func main() {ch := make(chan int)var wg sync.WaitGroupwg.Add(1)go func() {defer wg.Done()defer fmt.Println("close ch") // close chdefer close(ch)go func() {ch <- 1 // panic: send on closed channel}()}()fmt.Println(<-ch)wg.Wait()
}

不正确地关闭channel会导致程序panic,如何优雅关闭channel参看

参看:《How to Gracefully Close Channels》

总结

        本内容主要讲述了channel的基础知识包括定义使用背景类型操作方式使用场景不正确关闭channelpanic的场景没有对channel的底层实现原理进行解读参看channel的底层实现原理了解

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【ROS】参数服务器--理论模型与参数操作(C++)

一、概念介绍 参数服务器在ROS中主要用于实现不同节点之间的数据共享。参数服务器相当于是独立于所有节点的一个公共容器&#xff0c;可以将数据存储在该容器中&#xff0c;被不同的节点调用&#xff0c;当然不同的节点也可以往其中存储数据。 作用&#xff1a;存储一些多节点…

Qt实现简单的漫游器

文章目录 Qt的OpenGL窗口GLSL的实现摄像机类的实现简单的漫游器 Qt的OpenGL窗口 Qt主要是使用QOpenGLWidget来实现opengl的功能。  QOpenGLWidget 提供了三个便捷的虚函数&#xff0c;可以重载&#xff0c;用来重新实现典型的OpenGL任务&#xff1a; paintGL&#xff1a;渲染…

Datawhale Django后端开发入门 Vscode TASK02 Admin管理员、外键的使用

一.Admin管理员的使用 1、启动django服务 使用创建管理员之前&#xff0c;一定要先启动django服务&#xff0c;虽然TASK01和TASK02是分开的&#xff0c;但是进行第二个流程的时候记得先启动django服务&#xff0c;注意此时是在你的项目文件夹下启动的&#xff0c;时刻注意要执…

基于CentOS7.9安装部署docker(简洁版)

安装部署 1基于官方脚本安装&#xff08;不推荐 不能自行选择版本&#xff09; 官方文档&#xff1a;https://docs.docker.com/engine/install/centos/ 2 使用yum安装 阿里云文档&#xff1a;docker-ce镜像_docker-ce下载地址_docker-ce安装教程-阿里巴巴开源镜像站 # ste…

matlab使用教程(19)—曲线拟合与一元方程求根

1.多项式曲线拟合 此示例说明如何使用 polyfit 函数将多项式曲线与一组数据点拟合。您可以按照以下语法&#xff0c;使用 polyfit 求出以最小二乘方式与一组数据拟合的多项式的系数 p polyfit(x,y,n), 其中&#xff1a; • x 和 y 是包含数据点的 x 和 y 坐标的向量 …

【Linux操作系统】Linux系统编程中的共享存储映射(mmap)

在Linux系统编程中&#xff0c;进程之间的通信是一项重要的任务。共享存储映射&#xff08;mmap&#xff09;是一种高效的进程通信方式&#xff0c;它允许多个进程共享同一个内存区域&#xff0c;从而实现数据的共享和通信。本文将介绍共享存储映射的概念、原理、使用方法和注意…

uni-app的Vue.js实现微信小程序的紧急事件登记页面功能

主要功能实现 完成发生时间选择功能&#xff0c;用户可以通过日期选择器选择事件发生的时间。实现事件类型选择功能&#xff0c;用户可以通过下拉选择框选择事件的类型。添加子养殖场编号输入框&#xff0c;用户可以输入与事件相关的子养殖场编号。完成事件描述输入功能&#…

C++头文件

C头文件 一般头文件特殊头文件windows.hbits/stdc.h 一般头文件 C头文件是一种包含预定义函数、类和变量声明的文件。它们通常用于在源代码文件中引入外部库或模块的功能。 头文件的作用是提供程序所需的声明信息&#xff0c;以便在源代码文件中使用这些声明。当你在源代码文…

Android Studio实现解析HTML获取图片URL,将URL存到list,进行列表展示

目录 效果build.gradle(app)添加的依赖(用不上的可以不加)AndroidManifest.xml错误代码activity_main.xmlitem_image.xmlMainActivityImage适配器ImageModel 接收图片URL效果 build.gradle(app)添加的依赖(用不上的可以不加) dependencies {implementation com.square…

使用pnpm workspace管理Monorepo架构

在开发项目的过程中&#xff0c;我们需要在一个仓库中管理多个项目&#xff0c;每个项目有独立的依赖、脚手架&#xff0c;这种形式的项目结构我们称之为Monorepo&#xff0c;pnpm workspace就是管理这类项目的方案之一。 一、pnpm简介 1、pnpm概述 pnpm代表performance npm…

QT SSL handshake failed问题分析与解决 QT基础入门【网络编程】openssl

问题: 使用https方式进行post 和get请求时,有时候会出现SSL handshake failed的问题,其实是调用Qt QNetworkAccessManager出现的问题。 其实SSL握手是建立HTTPS连接过程的第一步。为了验证和建立连接,用户的浏览器和网站的服务器必须经过一系列检查(握手),从而建立HTTP…

OpenCV基础知识(6)— 滤波器

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。在尽量保留原图像信息的情况下&#xff0c;去除图像内噪声、降低细节层次信息等一系列过程&#xff0c;被叫做图像的平滑处理&#xff08;或者叫图像的模糊处理&#xff09;。实现平滑处理最常用的工具就是滤波器。通过调节…

RK3588平台开发系列讲解(AI 篇)RKNN C API 详细说明

文章目录 一、API 硬件平台支持说明二、API 函数介绍2.1、rknn_init2.2、rknn_destroy2.3、rknn_query2.4、rknn_inputs_set2.5、rknn_run2.6、rknn_outputs_get2.7、rknn_outputs_release沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇章主要讲解 RKNN C API 详细…

浅析基于视频汇聚与AI智能分析的新零售方案设计

一、行业背景 近年来&#xff0c;随着新零售概念的提出&#xff0c;国内外各大企业纷纷布局智慧零售领域。从无人便利店、智能售货机&#xff0c;到线上线下融合的电商平台&#xff0c;再到通过大数据分析实现精准推送的个性化营销&#xff0c;智慧零售的触角已经深入各个零售…

[Mac软件]MacCleaner 3 PRO 3.2.1应用程序清理和卸载

应用介绍 MacCleaner PRO是一个应用程序包&#xff0c;将帮助您清除磁盘空间并加快Mac的速度&#xff01; MacCleaner PRO - 让您的Mac始终快速、干净和有条理。 App Cleaner & Uninstaller PRO - 完全删除未使用的应用程序并管理Mac扩展。 磁盘空间分析仪PRO-分析磁盘空…

CMC、mAP解析:图像检索领域评价指标

1. CMC&#xff1a; Cumulative Matching Characteristics 累计匹配特征 CMC是一种计算 top-n 的评价指标&#xff0c;主要用来评估闭集中rank-n的正确率。 下面举例说明&#xff1a; 在双模态特征匹配中。底库 Gallery 中有10条数据&#xff08;label分别为1&#xff0c;2&am…

【数据结构OJ题】有效的括号

原题链接&#xff1a;https://leetcode.cn/problems/valid-parentheses/ 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 这道题目主要考查了栈的特性&#xff1a; 题目的意思主要是要做到3点匹配&#xff1a;类型、顺序、数量。 题目给的例子是比较…

Python web实战之Django 的跨站点请求伪造(CSRF)保护详解

关键词&#xff1a;Python、Web、Django、跨站请求伪造、CSRF 大家好&#xff0c;今天我将分享web关于安全的话题&#xff1a;Django 的跨站点请求伪造&#xff08;CSRF&#xff09;保护&#xff0c;介绍 CSRF 的概念、原理和保护方法. 1. CSRF 是什么&#xff1f; CSRF&#…

VBA技术资料MF43:VBA_Excel中自动填充

【分享成果&#xff0c;随喜正能量】以时寝息&#xff0c;当愿众生&#xff0c;身得安隐&#xff0c;心无动乱。愿我们都能&#xff0c;梦见幸福&#xff01;在踉跄中前进&#xff0c;在跌倒后跃进&#xff0c;逐渐强大.。 我给VBA的定义&#xff1a;VBA是个人小型自动化处理的…

Shell脚本基础( 四: sed编辑器)

目录 1 简介 1.1 sed编辑器的工作流程 2 sed 2.1 基本用法 2.2 sed基本格式 2.2.1 sed支持正则表达式 2.2.2 匹配正则表达式 2.2.3 奇数偶数表示 2.2.4 -d选项删除 2.2.5 -i修改文件内容 2.2.6 -a 追加 2.3 搜索替代 2.4 变量 1 简介 sed是一种流编辑器&#xff0c;…