go基础知识归纳总结

无缓冲的 channel 和有缓冲的 channel 的区别?

在 Go 语言中,channel 是用来在 goroutines 之间传递数据的主要机制。它们有两种类型:无缓冲的 channel 和有缓冲的 channel。

  1. 无缓冲的 channel

行为:无缓冲的 channel 是一种同步的通信方式,发送和接收必须同时发生。如果一个 goroutine 试图通过无缓冲 channel 发送数据,它会阻塞,直到另一个 goroutine 从该 channel 中接收数据。反之亦然,接收方在准备好接收数据之前,发送方无法继续执行。
用法:适合在两个 goroutines 之间实现精确的同步,确保它们在同一时刻传递数据。
优点:
保证了发送和接收的同步,可以避免某些类型的并发错误。
更简单,适合需要严格按顺序处理任务的场景。
缺点:
性能上可能存在瓶颈,因为必须等待对应的发送或接收操作才能继续执行。

无缓冲的 Channel 示例

package mainimport ("fmt""time"
)func main() {// 创建一个无缓冲的 channelch := make(chan int)// 启动一个 goroutine 来接收数据go func() {// 接收数据之前会阻塞,直到 main goroutine 发送数据val := <-chfmt.Println("接收到的数据:", val)}()// 模拟一些操作time.Sleep(1 * time.Second)// 发送数据到 channel,会阻塞直到接收方读取数据ch <- 42fmt.Println("数据已发送")
}

由于是无缓冲的 channel,main goroutine 在发送 42 时会阻塞,直到 goroutine 从 channel 中接收到这个值,程序才会继续执行。
2. 有缓冲的 channel

行为:有缓冲的 channel 容许在 channel 中存储一定数量的数据元素,发送方可以在 channel 未满时继续发送数据,而无需等待接收方。接收方只有当 channel 非空时才会接收数据。
用法:适合发送方和接收方的处理速度不一致的情况,允许发送方先发送一部分数据,接收方稍后接收。
优点:
提供了一定的并发灵活性,发送方可以在接收方未准备好时先发送一定数量的数据。
提高了性能,减少了因为同步阻塞而导致的性能损耗。
缺点:
如果缓冲区设计不当,可能会出现缓冲区溢出或浪费资源的情况。
由于有缓冲的存在,可能会导致发送和接收之间的时间不同步,增加调试和排查问题的难度。
总结
无缓冲的 channel 强调的是同步性,适合需要严格同步的场景。

有缓冲的 channel 提供更多的灵活性,允许在并发处理中有更大的自由度,不需要完全同步。
在使用中,可以根据具体场景选择合适的 channel 类型。例如,在生产者-消费者模型中,有缓冲的 channel 可以防止生产者等待消费者处理;而在需要精确同步的任务中,无缓冲 channel 则更加合适。

有缓冲的 Channel 示例

package mainimport ("fmt""time"
)func main() {// 创建一个带有缓冲区大小为 2 的 channelch := make(chan int, 2)// 发送两个数据到 channelch <- 1fmt.Println("发送了数据 1")ch <- 2fmt.Println("发送了数据 2")// 此时,由于缓冲区还有空间,发送不会阻塞go func() {// 延迟读取,模拟一些操作time.Sleep(2 * time.Second)val := <-chfmt.Println("接收到的数据:", val)}()// 继续发送数据time.Sleep(1 * time.Second)ch <- 3fmt.Println("发送了数据 3")// 接收数据time.Sleep(2 * time.Second)val := <-chfmt.Println("接收到的数据:", val)
}

这里的 channel 有缓冲区大小为 2,因此前两个 ch <- 操作不会阻塞,因为缓冲区有足够空间。第三次发送数据时,如果缓冲区已满,发送方会阻塞,直到接收方读取数据并释放空间。

channel和select底层数据结构是怎样的?

Go 中 select 语句的底层实现涉及多个关键数据结构和调度机制,主要是为了高效地处理通道(channel)操作和 Goroutine 调度。我们可以从 Go 语言的源代码中窥探其底层数据结构。以下是 select 相关的几个重要底层数据结构和其如何与通道和 Goroutine 协同工作:

  1. Goroutine 和 P 结构
    Go 的并发模型基于 Goroutine 和 M
    调度模型。每个 select 语句本质上都会涉及到 Goroutine 的阻塞与唤醒。调度器的核心数据结构包括:
    Goroutine(G):代表一个执行中的协程,每个 Goroutine 都包含了当前执行状态、栈信息等。当某个 select 语句阻塞 Goroutine 时,Goroutine 会被挂起,并与通道关联。
    P(Processor):代表一个运行 Goroutine 的处理器,它与 OS 线程(M)配合使用,管理并调度多个 Goroutine。
    当某个 select 语句涉及到通道的操作时,如果通道未就绪,当前 Goroutine 会被放入通道的等待队列中,并挂起,直到被调度器唤醒。
  1. 通道(Channel)结构
    通道的底层结构非常重要,因为 select 语句的核心在于处理通道操作。通道的内部结构如下
type hchan struct {qcount   uint           // 通道中已经存在的数据个数dataqsiz uint           // 环形队列的大小buf      unsafe.Pointer // 环形队列的指针elemsize uint16         // 每个元素的大小closed   uint32         // 通道是否关闭sendx    uint           // 发送操作的索引recvx    uint           // 接收操作的索引recvq    waitq          // 等待接收的 Goroutine 队列sendq    waitq          // 等待发送的 Goroutine 队列
}

recvq/sendq:表示接收和发送操作等待的 Goroutine 队列。当 select 语句中有对通道的接收或发送操作时,如果通道未就绪,当前 Goroutine 会被加入相应的等待队列。

  1. SelectCase 结构
    Go 运行时使用一个名为 SelectCase 的数据结构来表示 select 语句中的每个 case,每个 SelectCase 代表一个通道操作。该结构体中记录了每个 case 中的通道、操作类型(发送或接收)以及相关的数据指针等。
type scase struct {c    *hchan         // 指向通道的指针kind uint16         // 操作类型(发送、接收)pc   uintptr        // 程序计数器,用于跟踪执行位置elem unsafe.Pointer // 数据元素的指针,用于发送或接收操作
}

c:指向通道的指针,表示这个 case 监听哪个通道。
kind:表示操作类型,是发送、接收还是默认 case。
elem:存储数据的指针,用于发送或接收操作时的存取。

  1. Select 语句的执行流程
    当 Goroutine 执行一个 select 语句时,Go 运行时会执行以下操作:
    初始化 scase 列表:首先,select 语句会初始化每个通道操作,生成一个 scase 列表来表示所有的 case。
    检测是否有就绪通道:然后,运行时会遍历这些 scase,检测是否有通道已经就绪(比如是否有数据可接收,或者通道是否可以发送数据)。如果有通道就绪,立刻执行相应的操作,并返回。
    阻塞等待:如果所有通道都未就绪,当前 Goroutine 会挂起并加入到每个通道的等待队列中。此时,通道内部的 recvq 或 sendq 队列会保存当前 Goroutine 的相关信息,当通道状态发生变化时,这些队列会被唤醒,调度器会重新调度等待的 Goroutine 。
    随机选择通道:当有多个通道同时就绪时,Go 运行时通过随机函数来选择一个通道执行,保证公平性。
  2. 调度器与 select
    Go 调度器通过一组全局的队列和局部队列来管理 Goroutine 的运行状态。在 select 语句中,阻塞的 Goroutine 会被挂起到通道的等待队列中,但它们仍然保留在全局或局部队列中。当通道状态发生变化(如通道中有数据),调度器会从队列中唤醒相关的 Goroutine 并将其重新加入执行队列。
  3. select 的公平性和随机性
    Go 在 select 中实现了对多个通道操作的随机选择机制,避免某些通道操作被长期饿死。具体来说,当有多个通道同时就绪时,Go 会打乱 scase 列表的顺序,并随机选择一个通道进行处理。这确保了 select 的公平性,即使多个 Goroutine 同时监听同一组通道,也不会导致某个通道长期得不到处理。

select 的核心数据结构总结
Goroutine (G):Goroutine 是 select 语句中的执行单元,当一个 select 阻塞时,当前 Goroutine 会挂起。
hchan:通道是核心数据结构,负责管理发送和接收操作,recvq 和 sendq 队列保存了等待通道操作的 Goroutine。
scase:select 语句中每个通道操作的表示,存储了通道的指针、操作类型等信息。
调度器:Go 调度器负责管理 Goroutine 的执行和状态,当 select 语句涉及到阻塞操作时,调度器会将 Goroutine 挂起并重新调度。
通过这些底层机制,Go 的 select 语句能够高效地在并发场景下处理多个通道操作,并且在多个通道就绪时提供随机选择的公平性保障。

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

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

相关文章

如何让Windows控制台窗口不接受鼠标点击(禁用鼠标输入)

一、简述 在我们编写控制台应用程序时&#xff0c;默认情况下程序的打印输出会在控制台窗口中进行显示&#xff0c;我们在写服务功能时在窗口中会不断打印消息输出&#xff0c;这个时候如果使用鼠标点击了控制台窗口&#xff0c;会阻塞程序的继续运行&#xff0c;导致我们的程…

C#-使用Serilog框架快速实现日志及其相关扩展

目录 一、Serilog日志实现 1、实现 ILogEventSink接口 2、日志类Log 3、日志级别LogLevel 4、ILogger接口 5、日志服务实现 6、日志视图View 7、ViewModel 二、功能扩展 1、日志扩展方法 2、Trace追踪扩展日志 3、自动滚动至底部 一、Serilog日志实现 安装NuGet包…

SpringBoot集成Thymeleaf模板引擎,为什么使用(详细介绍)

学习本技术第一件事&#xff1a;你为什么要使用&#xff0c;解决什么问题的&#xff1f; 1.为什么使用&#xff08;使用背景&#xff09;&#xff1f; 首先应用场景是单体项目&#xff0c;如果是前后端分离就不用关注这个了&#xff0c;因为单体项目你前后端都是写在一个项目…

性能小白终于能看懂Jmeter报告了

对于刚接触性能测试的初学者来说&#xff0c;分析JMeter生成的测试报告无疑是一个巨大的挑战。面对大量的数据信息&#xff0c;如何快速理解响应时间、吞吐量、错误率等关键指标&#xff0c;往往让人感到困惑。今天&#xff0c;让我们一起探讨如何轻松看懂JMeter的性能测试报告…

ResNet(Residual Network)网络介绍

1. ResNet的背景与创新&#xff1a; ResNet是由微软研究院的何恺明等人在2015年提出&#xff0c;并在ILSVRC&#xff08;ImageNet Large Scale Visual Recognition Challenge&#xff09;中取得了冠军。这一网络结构的提出&#xff0c;标志着深度学习领域的一个重要突破&#x…

多线程篇(其它容器- CopyOnWriteArrayList)(持续更新迭代)

一、CopyOnWriteArrayList&#xff08;一&#xff09; 1. 简介 并发包中的并发List只有CopyOnWriteArrayList。 CopyOnWriteArrayList是一个线程安全的ArrayList&#xff0c;对其进行的修改操作都是在底层的一个复制的数 组&#xff08;快照&#xff09;上进行的&#xff0…

HTML5下<hr>标签的CSS样式定制

引言 在HTML中&#xff0c;<hr>标签扮演着分隔内容的重要角色。作为水平线标签&#xff0c;<hr>在视觉上将文档分隔成各个部分&#xff0c;帮助用户更好地理解页面内容。本文将深入解析<hr>标签的定义、用法、属性以及在不同HTML规范中的地位和浏览器兼容性…

基于STM32C8T6的CubeMX:HAL库点亮LED

三个可能的问题和解决方法&#xff1a; 大家完成之后回来看&#xff0c;每一种改错误都是一种成长&#xff0c;不要畏惧&#xff0c;要快乐&#xff0c;积极面对&#xff0c;要耐心对待 STMCuBeMX新建项目的两种匪夷所思的问题https://mp.csdn.net/mp_blog/creation/editor/1…

【Android 13源码分析】WindowContainer窗口层级-1-初识窗口层级树

在安卓源码的设计中&#xff0c;将将屏幕分为了37层&#xff0c;不同的窗口将在不同的层级中显示。 对这一块的概念以及相关源码做了详细分析&#xff0c;整理出以下几篇。 【Android 13源码分析】WindowContainer窗口层级-1-初识窗口层级树 【Android 13源码分析】WindowCon…

基于STM32的汽车仪表显示系统:集成CAN、UART与I2C总线设计流程

一、项目概述 项目目标与用途 本项目旨在设计和实现一个基于STM32微控制器的汽车仪表显示系统。该系统能够实时显示汽车的速度、转速、油量等关键信息&#xff0c;并通过CAN总线与其他汽车控制单元进行通信。这种仪表显示系统不仅提高了驾驶的安全性和便捷性&#xff0c;还能…

前端技术(七)——less 教程

一、less简介 1. less是什么&#xff1f; less是一种动态样式语言&#xff0c;属于css预处理器的范畴&#xff0c;它扩展了CSS语言&#xff0c;增加了变量、Mixin、函数等特性&#xff0c;使CSS 更易维护和扩展LESS 既可以在 客户端 上运行 &#xff0c;也可以借助Node.js在服…

Semaphore UI --Ansible webui

1、安装python python下载地址 https://www.python.org/downloads/ 选好版本下载 wget https://www.python.org/ftp/python/3.11.9/Python-3.11.9.tar.xz安装编译工具 sudo dnf groupinstall "Development Tools"安装依赖包 dnf install bzip2-devel ncurses-deve…

IDEA 常用配置和开发插件

件市场中搜索并安装“Git Integration”插件。 一、前言 在本篇文章中我会为大家总结一些我自己常用的配置和开发插件&#xff0c;此外也给大家提供一个建议&#xff0c;可以根据自己的项目需求和个人偏好选择适合的插件。另外&#xff0c;IDEA 也在不断更新&#xff0c;可能会…

哈希表、算法

哈希表 hash&#xff1a; 在编程和数据结构中&#xff0c;"hash" 通常指的是哈希函数&#xff0c;它是一种算法&#xff0c;用于将数据&#xff08;通常是字符 串&#xff09;映射到一个固定大小的数字&#xff08;哈希值&#xff09;。哈希函数在哈希表中尤为重要…

使用vue2+axios+chart.js画折线图 ,出现 RangeError: Maximum call stack size exceeded 错误

目录 效果图 解决方案 修正要点 效果图 修改前App.vue代码&#xff1a; <template><div id"app"><canvas id"myChart"></canvas></div> </template><script> import axios from axios; import { Chart, regis…

中级练习[7]:Hive SQL

目录 1. 统计每天男性和女性用户的订单总金额 1.1 题目需求 1.2 代码实现 2. 订单金额趋势分析 2.1 题目需求 2.2 代码实现 3. 购买过商品1和商品2但是没有购买商品3的顾客 3.1 题目需求 3.2 代码实现 1. 统计每天男性和女性用户的订单总金额 1.1 题目需求 从订单信…

stm32 W25Q数据存储

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、cubemx配置二、keil中文件修改与配置三、几个重要函数的说明四、DMA方式传输&#xff08;待写&#xff09;总结 前言 W25Q128 容量为128位 128/8 16 也就…

Mac 上终端使用 MySql 记录

文章目录 下载安装终端进入 MySql常用操作查看数据库选择一个数据库查看当前选择的数据库Navcat 打开提示报错参考文章 下载安装 先下载社区版的 MySql 安装的过程需要设置 root 的密码&#xff0c;这个是要进入数据库所设定的&#xff0c;所以要记住 终端进入 MySql 首先输…

Linux基础-Makefile的编写、以及编写第一个Linux程序:进度条(模拟在 方便下载的同时,更新图形化界面)

目录 一、Linux项目自动化构建工具-make/Makefile ​编辑 背景&#xff1a; makefile小技巧&#xff1a; 二、Linux第一个小程序&#xff0d;进度条 先导&#xff1a; 1.如何利用/r,fflush(stdout)来实现我们想要的效果&#xff1b; 2.写一个倒计时&#xff1a; 进度条…

智能家居环境监测系统设计(论文+源码)

1. 系统方案 系统由9个部分构成&#xff0c;分别是电源模块、烟雾传感器模块、GSM发送短信模块、报警模块、温度传感器模块、人体红外感应模块、按键设置模块、显示模块、MCU模块。各模块的作用如下&#xff1a;电源模块为系统提供电力&#xff1b;烟雾传感器模块检测烟雾浓度&…