【魅力golang】之-通道

昨天发布了golang的最大特色之一--协程,与协程密不可分的是通道(channel),用来充当协程间相互通信的角色。通道是一种内置的数据结构,所以才造就了golang强大的并发能力。今天风云来爬一爬通道的详细用法。

通道在golang中也叫协程间通信原语。通过通道,协程可以安全、同步地交换数据,避免直接操作共享内存带来的复杂性。

1、通道的特征:

类型化:通道是一个类型化的管道,数据只能按特定类型传递。

阻塞同步发送操作如果通道满了,发送方会阻塞,直到有协程接收数据。接收操作如果通道为空,接收方会阻塞,直到有数据写入。

无锁并发:通道内部实现了无锁队列和条件变量,确保高效的并发操作。

2、通道的设计思路

基于 CSP 模型:Go 的通道实现了 Communicating Sequential Processes(CSP) 并发模型,将共享内存的问题转化为通信问题。

核心思想:“不要通过共享内存来通信,而是通过通信来共享内存。”

3、通道的作用

  • 提供一种安全的协程间通信机制。
  • 避免复杂的加锁操作。
  • 支持同步(无缓冲)和异步(缓冲)通信。
  • 实现协程间的消息队列、信号传递、负载均衡等功能。

4、 通道的用法

4.1 创建通道

  • 使用 make 创建通道。
  • 语法:ch := make(chan T),其中 T 是通道中数据的类型。

示例:创建无缓冲通道

package mainimport "fmt"func main() {ch := make(chan int) // 无缓冲通道fmt.Println("Channel created:", ch)
}

4.2 通道的基本操作

  1. 发送数据:通过 ch <- value 向通道发送数据。
  2. 接收数据:通过 value := <-ch 从通道接收数据。
  3. 关闭通道:使用 close(ch) 关闭通道,表示不会再发送数据。

示例:基本发送与接收

package mainimport "fmt"func main() {ch := make(chan int)// 启动一个协程发送数据go func() {ch <- 42 // 发送一个整数值}()// 接收数据value := <-chfmt.Println("Received value:", value) // 输出:Received value: 42
}

4.3 无缓冲通道

  • 无缓冲通道的发送和接收操作是同步的。
  • 发送方和接收方必须同时准备好,操作才能完成。

示例:无缓冲通道的阻塞特性

package mainimport ("fmt"
)func main() {ch := make(chan string)  // 创建一个无缓冲的通道go func() {fmt.Println("Sending message...")ch <- "Hello, Channel!" // 发送方阻塞,直到接收方准备好fmt.Println("Message sent!")}()message := <-ch // 接收操作fmt.Println("Received message:", message)  // 接收方阻塞,直到发送方发送消息
}

输出:

Sending message...
Message sent!
Received message: Hello, Channel!

4.4 缓冲通道

  • 缓冲通道允许存储固定数量的数据,发送方只有在缓冲区满时才会阻塞。

示例:缓冲通道

package mainimport ("fmt"
)func main() {ch := make(chan int, 3) // 创建一个容量为 3 的缓冲通道ch <- 1  // 发送数据ch <- 2  ch <- 3fmt.Println("All values sent")fmt.Println(<-ch) // 接收数据fmt.Println(<-ch)fmt.Println(<-ch)
}

输出:

All values sent
1
2
3

4.5 单向通道

  • 单向通道用于限制通道的操作。
    • 只发送:chan<- T
    • 只接收:<-chan T

示例:单向通道

package mainimport "fmt"func sendOnly(ch chan<- int) {ch <- 42 // 发送值fmt.Println("Value sent")
}func receiveOnly(ch <-chan int) {value := <-ch // 接收值fmt.Println("Value received:", value) // 这里会执行
}func main() {ch := make(chan int) //创建通道go sendOnly(ch) //发送值receiveOnly(ch) //接收值
}

输出:

Value sent
Value received: 42

4.6 通道的关闭

  • 使用 close(ch) 关闭通道。
  • 接收数据时,使用 v, ok := <-ch 检查通道是否已关闭。

示例:关闭通道

package mainimport "fmt"func main() {ch := make(chan int) // 创建一个通道go func() {for i := 0; i < 5; i++ {ch <- i // 向通道发送数据}close(ch) // 关闭通道}()for v := range ch { // 使用 range 遍历通道fmt.Println(v) // 输出接收到的数据}fmt.Println("Channel closed")
}

输出:

0
1
2
3
4
Channel closed

5、 通道的应用场景

5.1 消息队列

通道可以实现简单的消息队列,用于协程间的任务分发。

示例:通道实现消息队列

package mainimport ("fmt""time"
)func worker(id int, tasks <-chan int) {for task := range tasks {fmt.Printf("Worker %d processing task %d\n", id, task)time.Sleep(500 * time.Millisecond) // 模拟任务耗时}
}func main() {tasks := make(chan int, 10)// 启动多个协程for i := 1; i <= 3; i++ {go worker(i, tasks)}// 向通道发送任务for i := 1; i <= 10; i++ {tasks <- i}close(tasks) // 关闭通道,表示不再发送任务time.Sleep(3 * time.Second) // 等待所有任务完成
}

输出:

Worker 3 processing task 2
Worker 2 processing task 3
Worker 1 processing task 1
Worker 1 processing task 4
Worker 2 processing task 6
Worker 3 processing task 5
Worker 2 processing task 7
Worker 1 processing task 8
Worker 3 processing task 9
Worker 3 processing task 10

5.2 协程通信

通道用于协程间的安全通信,避免使用共享变量。

示例:通道实现协程通信

package mainimport ("fmt""sync"
)func worker(id int, ch chan int, wg *sync.WaitGroup) {defer wg.Done() // 减少计数器for num := range ch { // 从通道中接收数据fmt.Printf("Worker %d received: %d\n", id, num)}
}func main() {var wg sync.WaitGroup // 用于等待所有协程完成ch := make(chan int) // 定义一个通道// 启动协程for i := 1; i <= 3; i++ { // 启动3个协程wg.Add(1) // 增加计数器go worker(i, ch, &wg) // 启动协程}// 发送数据for i := 1; i <= 10; i++ { // 发送10个数据ch <- i // 将数据发送到通道}close(ch) // 关闭通道,通知协程退出wg.Wait() // 等待所有协程完成fmt.Println("All workers finished")
}

输出:

Worker 3 received: 1
Worker 3 received: 4
Worker 3 received: 5
Worker 3 received: 6
Worker 3 received: 7
Worker 3 received: 8
Worker 3 received: 9
Worker 2 received: 3
Worker 1 received: 2
Worker 3 received: 10
All workers finished

5.3 定时器和信号通知

通道结合 time 包可以实现超时控制和信号通知。

示例:超时控制

package mainimport ("fmt""time"
)func main() {ch := make(chan int) // 无缓冲go func() {time.Sleep(2 * time.Second) // 模拟耗时ch <- 42 // 发送数据}()select { // 等待接收数据或超时case value := <-ch: // 接收数据fmt.Println("Received value:", value)case <-time.After(1 * time.Second): // 超时处理fmt.Println("Timeout")}
}

输出:Timeout

6、注意事项

避免写入关闭的通道:对已关闭的通道写入数据会导致 panic。

通道的死锁问题:如果所有接收者都退出,而发送者仍在发送,会导致死锁。

容量规划:合理规划缓冲通道的容量,避免频繁阻塞。

数据泄露:确保通道关闭后协程正确退出,避免资源泄露。

Golang 中的通道是实现协程间通信的核心工具,简化了并发编程的复杂性。通道通过 CSP 模型实现协程间的数据传递,在消息队列、协程同步、超时控制等场景中表现出色。合理使用通道能有效提高程序的并发能力和可维护性。

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

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

相关文章

【论文复现】农作物病害分类(Web端实现)

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀ 农作物病害分类 概述演示效果核心逻辑使用方式部署方式 概述 农作物病害是国家粮食安全的一个主要威胁&#xff0c;是决定农作物产量和质量的…

Linux网络——网络基础

Linux网络——网络基础 文章目录 Linux网络——网络基础一、计算机网络的发展背景1、网络的定义&#xff08;1&#xff09; 独立模式&#xff08;2&#xff09;网络互联 2、局域网 LAN3、广域网 WAN4、比较局域网和广域网5、扩展 —— 域域网和互联网 二、协议1、协议的概念2、…

Reactor

文章目录 正确的理解发送double free问题 1.把我们的reactor进行拆分2.链接管理3.Reactor的理论 listensock只需要设置_recv_cb&#xff0c;而其他sock&#xff0c;读&#xff0c;写&#xff0c;异常 所以今天写nullptr其实就不太对&#xff0c;添加为空就没办法去响应事件 获…

Linux -- 线程的优点、pthread 线程库

目录 线程的优点 pthread 线程库 前言 认识线程库 简单验证线程的独立栈空间 线程的优点 与进程之间的切换相比&#xff0c;线程之间的切换需要操作系统做的工作要少得多。 调度进程时&#xff0c;CPU 中有一个 cache&#xff08;缓存&#xff0c;提高运行效率&#xff0…

centos权限大集合,覆盖多种权限类型,解惑权限后有“. + t s”问题!

在 CentOS 系统中&#xff0c;权限管理是操作系统的核心功能之一&#xff0c;确保不同用户和进程对文件、目录以及设备的访问被合理控制。 权限系统主要包括传统的 Unix 权限模型、特殊权限&#xff08;SetUID、SetGID、Sticky 位&#xff09;和更精细的访问控制列表&#xff…

pyinstaller打包资源文件和ini配置文件怎么放

1.如果出现无法成功完成操作&#xff0c;因为文件包含病毒或潜在的垃圾软件&#xff0c;说明你的版本太高&#xff0c;更换pyinstaller版本。 pip install pyinstaller6.2.02.一开始打包的时windows下尽量选择打成文件夹的并且要是带命令行窗口的&#xff0c;容易查看错误。 …

五种msvcr100.dll丢失的解决方法,有效修复msvcr100.dll丢失错误!跟msvcr100.dll错误问题说拜拜!

在日常电脑使用过程中&#xff0c;尤其是运行某些应用程序或游戏时&#xff0c;可能会遇到“msvcr100.dll丢失”的错误提示。这个动态链接库&#xff08;DLL&#xff09;文件是Microsoft Visual C Redistributable for Visual Studio 2010的一部分&#xff0c;对于许多程序的正…

【前端】入门指南:Vue中使用Node.js进行数据库CRUD操作的详细步骤

&#x1f4a5; 欢迎来到我的博客&#xff01;很高兴能在这里与您相遇&#xff01; 首页&#xff1a;GPT-千鑫 – 热爱AI、热爱Python的天选打工人&#xff0c;活到老学到老&#xff01;&#xff01;&#xff01;导航 - 人工智能系列&#xff1a;包含 OpenAI API Key教程, 50个…

【网络安全产品大调研系列】1. 漏洞扫描

1. 为什么会出现漏扫技术&#xff1f; 每次黑客攻击事件进行追溯的时候&#xff0c;根据日志分析后&#xff0c;我们往往发现基本都是系统、Web、 弱口令、配置这四个方面中的其中一个出现的安全问题导致黑客可以轻松入侵的。 操作系统的版本滞后&#xff0c;没有更新补丁&am…

Java爬虫:速卖通(AliExpress)商品评论获取指南

引言 在当今的电商时代&#xff0c;商品评论对于消费者决策有着举足轻重的影响。速卖通&#xff08;AliExpress&#xff09;&#xff0c;作为全球知名的在线零售平台之一&#xff0c;拥有海量的商品评论数据。对于商家而言&#xff0c;能够高效地获取这些评论数据&#xff0c;…

AIDD - 探索语言模型在药物分子生成方面的应用

AIDD - 探索语言模型在药物分子生成方面的应用 今天给大家讲一篇2024年10月在nature communications上发表的一篇关于分子生成的文章。现有的分子生成方法中往往只关注药物的特定属性&#xff0c;导致其适用性受限。因此作者提出了TamGen方法&#xff0c;用于针对特定靶点的分子…

【每日学点鸿蒙知识】AVCodec、SmartPerf工具、web组件加载、监听键盘的显示隐藏、Asset Store Kit

1、AVCodec 硬解咨询&#xff1f; 在做视频播放硬解适配&#xff0c;这是 demo&#xff1a;https://gitee.com/openharmony-sig/ohos_videocompressor/blob/master/videoCompressor/src/main/cpp/video/decoder/VideoDec.cpp 请问&#xff1a; int32_t VideoDec::SetOutputS…

怎么设置电脑密码?Windows和Mac设置密码的方法

为电脑设置密码是保护个人信息安全的重要措施。无论是Windows系统还是MacOS系统&#xff0c;设置密码的步骤都相对简单&#xff0c;但需要根据不同的操作系统选择不同的方法。 一、Windows系统电脑密码设置 方法一&#xff1a;通过控制面板设置账户密码 点击桌面左下角的“开…

谷歌浏览器的网络安全检测工具介绍

作为全球最受欢迎的浏览器之一&#xff0c;谷歌浏览器不仅提供了快速、便捷的浏览体验&#xff0c;还内置了一系列强大的网络安全检测工具&#xff0c;帮助用户识别潜在的网络威胁&#xff0c;保护个人隐私和数据安全。本文将详细介绍谷歌浏览器中的几项关键网络安全检测功能&a…

一个比RTK或redux更轻量级更易使用的 React 第三方状态管理工具库的配置与使用

本文由作者 Samdy_Chan 原创,未经作者同意,请勿随意转载! 使用轻量级第三方的 React 状态管理库 zustand 管理共享状态数据 在 react 框架应用中,开发者应该大多数都是采用 redux 状态管理工具库来管理应用的共享状态数据,但用过 redux 的人都知道,其配置和使用相当复杂…

菜鸟带新鸟——基于EPlan2022的部件库制作

首先&#xff0c;我们需要了解一些概念&#xff1a; Eplan的部件制作内容 以上内容是制作一个完整的部件所需要的。如果公司要求没有那么严格&#xff0c;我们就可以制作1-4级的内容就可以满足日常的使用啦&#xff01; 部件的创建方式 部件创建方式有4类&#xff1a; 1、单…

Charles安装证书过程(手机)

背景&#xff1a;使用模拟器抓包时&#xff0c;发现https请求无法抓取&#xff0c;需要安装相应证书。我自己是因为模拟器升级了安卓7&#xff0c;发现之前安装的证书无效了&#xff0c;需要重新安装。 参考博客&#xff1a;夜神模拟器12Charles进行Https抓包_模拟器抓包ssl-C…

Windows、CentOS环境下搭建自己的版本管理资料库:GitBlit

可以搭建属于公司内部或者个人的Git服务器&#xff0c;方便程序代码及文档版本管理。 官网&#xff1a;http://www.gitblit.com/ Windows环境下安装 提前已经安装好了JDK。 官网下载Windows版的GitBlit。 将zip包解压到自己想要放置的文件夹下。 建立版本库路径&#xff0c…

数据库操作【JDBC HIbernate Mybatis】

JDBC JDBC编程 在java开发中&#xff0c;以前都是通过JDBC&#xff08;Java Data Base Connectivity&#xff09;与数据库打交道的&#xff0c;至少在ORM&#xff08;Object Relational Mapping&#xff09;框架没出现之前是这样&#xff0c;目前常用的ORM框架有JPA、hibernat…

Linux 常见用例汇总

注&#xff1a;本文为 Linux 常见用例文章合辑。 部分内容已过时&#xff0c;未更新整理。 检查 Linux 上的 glibc 版本 译者&#xff1a;joeren | 2014-11-27 21:33 问&#xff1a;检查 Linux 系统上的 GNU C 库&#xff08;glibc&#xff09;的版本&#xff1f; GNU C 库&…