Go语言的 的并发编程(Concurrency)核心知识

Go语言的并发编程(Concurrency)核心知识

引言

在现代软件开发中,性能与效率是开发者们面临的主要挑战之一。并发编程是一种在多核处理器上充分利用计算资源的方法,而Go语言(通常称为Golang)则以其强大的并发特性而受到广泛欢迎。Go语言自其诞生之日起便将并发编程作为设计的一项核心原则,提供了一种简单而高效的方式来处理并发操作。本文将深入探讨Go语言中的并发编程核心知识,帮助开发者更好地理解如何在Go中实现并发。

1. 并发与并行的区别

在深入Go的并发编程之前,首先需要明确并发(Concurrency)与并行(Parallelism)的区别:

  • 并发是指在同一时间段内处理多个任务的能力。并发可以是在单个核上通过任务切换实现的,也可以是在多个核上同时执行多个任务。
  • 并行则是指在同一时刻同时执行多个任务,这通常需要多核处理器的支持。

Go语言通过轻量级的goroutine实现并发,使得开发者能够在并发编程中更容易地管理多个任务。

2. goroutine:Go的并发基础

2.1 什么是goroutine?

goroutine是Go语言内置的一种轻量级线程。与传统线程相比,goroutine占用的资源更少,创建和销毁的成本也低得多。我们只需使用go关键字就可以启动一个新的goroutine。

go go func() { fmt.Println("Hello from goroutine") }()

2.2 goroutine的管理

Go运行时可以管理大量的goroutine,通常一个Go应用可以轻松启动成千上万的goroutine而无需担心性能问题。Go的调度器会在内核线程之间高效地调度这些goroutine,使得它们能够并发执行。

2.3 goroutine的调度模型

Go使用GOMAXPROCS设置最大可用CPU核心数,默认值是CPU核心数。当运行多个goroutine时,Go运行时会将这些goroutine分配到可用的CPU核心上。开发者可以通过以下方式设置GOMAXPROCS:

go runtime.GOMAXPROCS(4) // 设置使用4个CPU核心

3. 通信:channel

在并发编程中,通信是至关重要的,Go语言通过channel提供了一种安全且高效的方式来进行通信。

3.1 什么是channel?

channel是一种Go语言特有的数据类型,用于在多个goroutine之间传递数据。它可以理解为一个管道,goroutine能够通过这个管道发送和接收数据。

3.2 创建和使用channel

我们可以使用内置的make函数创建channel,语法如下:

go ch := make(chan int) // 创建一个传递int类型数据的channel

通过<-运算符,可以向channel发送数据或接收数据:

```go // 发送数据 ch <- 1

// 接收数据 value := <-ch ```

3.3 channel的方向

在Go中,我们可以定义channel的方向,以增强代码的可读性和安全性。可以将channel参数设置为只写或只读:

```go func sendData(ch chan<- int) { ch <- 1 }

func receiveData(ch <-chan int) int { return <-ch } ```

3.4 buffer与无缓冲channel

channel可以是有缓冲的或无缓冲的。无缓冲的channel在发送和接收数据时会阻塞,直到双方都准备好。创建无缓冲channel的方式如下:

go ch := make(chan int) // 无缓冲channel

而有缓冲的channel则允许指定缓冲区大小,例如:

go ch := make(chan int, 10) // 有缓冲区大小为10的channel

4. select语句

在Go语言中,select语句提供了一种处理多个channel操作的方式。它允许开发者等待多个channel操作中的任意一个完成。

4.1 基本用法

select语句的基本结构如下:

go select { case msg1 := <-ch1: fmt.Println("Received", msg1) case msg2 := <-ch2: fmt.Println("Received", msg2) case ch3 <- 3: fmt.Println("Sent 3 to ch3") default: fmt.Println("No communication") }

在这个例子中,select会等待ch1ch2的消息,或尝试向ch3发送数据。若没有任何通信,则执行default分支。

4.2 select的阻塞与非阻塞

如果没有任何case准备就绪,select会阻塞直到其中一个case准备就绪。利用default分支,可以实现非阻塞的多路径选择。

4.3 关闭channel

当不再需要channel时,应及时关闭它,以避免资源浪费。可以使用close函数关闭channel:

go close(ch)

请注意,在关闭channel后,不应再向其发送数据,但仍然可以从中接收数据。

5. 错误处理与恢复

在并发编程中,错误处理尤其重要,因为多个goroutine同时运行时,某个goroutine的错误可能会影响其他goroutine。Go提供了deferpanicrecover机制来处理错误。

5.1 defer

defer语句用于在函数执行完毕后执行指定的语句。常用于资源清理、关闭文件等操作。

go defer func() { fmt.Println("Cleanup") }()

5.2 panic和recover

在Go中,如果发生不可恢复的错误,可以使用panic触发一个运行时错误,而通过recover可以在执行defer语句时捕获到panic事件,从而恢复程序。

go func safeCall() { defer func() { if r := recover(); r != nil { fmt.Println("Recovered from", r) } }() panic("Something went wrong!") }

6. 设计模式与并发控制

在Go语言中,设计模式可以帮助我们更好地进行并发控制。以下是几种常见的并发设计模式。

6.1 Worker Pool

Worker Pool模式用于限制同时运行的goroutine数量,控制资源的使用。通过创建一定数量的worker goroutine,来处理任务队列中的工作。

```go const numWorkers = 3 tasks := make(chan Task)

for i := 0; i < numWorkers; i++ { go func() { for task := range tasks { task.Execute() } }() }

// 添加任务到channel中 for _, task := range tasksList { tasks <- task } close(tasks) ```

6.2 Fan-out/Fan-in

Fan-out/Fan-in模式用于将不同来源的多个功能合并到一个输出中。可以通过多个输入channel来承担负载,然后将结果汇集到一个通道中。

6.3 Pipeline

Pipeline模式允许将数据通过多个阶段处理,通过将每个阶段的输出直接连接到下一个阶段的输入来实现。

```go func stage1(in <-chan int) <-chan int { out := make(chan int) go func() { for i := range in { out <- process(i) } close(out) }() return out }

func main() { input := make(chan int) go func() { for _, i := range []int{1, 2, 3} { input <- i } close(input) }()

output := stage1(input)
for result := range output {fmt.Println(result)
}

} ```

7. 总结

Go语言的并发编程为开发者提供了强大而灵活的工具,使得并发编程的实现变得简单。在本文中,我们探讨了goroutine、channel、select语句以及错误处理的基本概念。同时,还介绍了常见的并发设计模式,帮助开发者更有效地管理资源和任务。

通过理解并掌握这些核心知识,开发者能够构建出高效且可扩展的并发应用程序,为现代软件开发带来更大的价值。随着对Go语言并发编程的深入研究,确保在多核环境中充分利用计算资源将成为未来开发者的重要技能之一。

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

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

相关文章

【调试记录】在CARLA中插入可以播放视频的组件

〇、问题描述 做实验验证的时候&#xff0c;需要在CARLA仿真环境中添加一个可以播放视频的功能&#xff0c;查了很多现有的实验&#xff0c;基本都是插入图像&#xff0c;而对于插入视频&#xff0c;实现的方法就很麻烦了。一开始考虑的是直接用射影变换进行叠加&#xff0c;计…

SQL—Group_Concat函数用法详解

SQL—Group_Concat函数用法详解 在LC遇见的一道很有趣的SQL题&#xff0c;有用到这个函数&#xff0c;就借这道题抛砖引玉&#xff0c;在此讲解一下group_concat函数的用法。&#x1f923; GROUP_CONCAT([DISTINCT] expression [ORDER BY expression] [SEPARATOR separator])…

深入解析 Linux 设备树中的引脚控制(pinctrl)二

在嵌入式开发中,设备树(Device Tree)是描述硬件设备和系统拓扑的重要结构。而在 Linux 内核中,引脚控制(pinctrl)是一个关键的硬件资源管理部分,负责管理和配置设备的引脚(GPIO、I2C、SPI 等接口)功能和状态。设备树通过描述这些引脚的特性,指导 Linux 内核如何正确地…

MySQL(六)MySQL 案例

1. MySQL 案例 1.1. 设计数据库 1、首先根据相关业务需求(主要参考输出输入条件)规划出表的基本结构   2、根据业务规则进行状态字段设计   3、预估相关表的数据量进行容量规划   4、确定主键   5、根据对相关处理语句的分析对数据结构进行相应的变更。   设计表的时…

后台管理系统动态面包屑Breadcrumb组件的实现

在后管理系统开发中&#xff0c;面包屑导航是一个非常常见的功能&#xff0c;通常是根据当前的 url 自动生成面包屑导航菜单&#xff0c;当跳转路由发生变化时&#xff0c;面包屑导航都会随之发生变化&#xff0c;即动态面包屑。 要完成动态面包屑我们需要制作一个动态数组&am…

4.1.2 栈和队列(一)

文章目录 栈的定义栈的基本运算栈的存储结构栈的应用表达式求值 栈和队列的逻辑结构与线性表相同&#xff0c;但是其运算受到限制&#xff0c;统称为运算受限的线性表。 栈&#xff0c; 先进后出 队列&#xff0c;先进先出 栈的定义 栈顶&#xff0c;唯一能操作端 栈底&#xf…

基于氢氧燃料电池的分布式三相电力系统Simulink建模与仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 5.完整工程文件 1.课题概述 基于氢氧燃料电池的分布式三相电力系统Simulink建模与仿真&#xff0c;仿真输出燃料电池中氢氧元素含量变化以及生成的H2O变化情况。 2.系统仿真结果 3.核心程序与模型 版本…

k620老显卡,装cuda.等。

CUDA安装教程&#xff08;超详细&#xff09;-CSDN博客 1.下载支持12.0以上的驱动 NVIDIA RTX Driver Release 550 R550 U12 (553.50) | Windows 11 解压。安装。一路下一步。查看结果 2.下载 cuda CUDA Toolkit Archive | NVIDIA Developer 安装cuda时&#xff0c;第一次…

【数学建模笔记】评价模型-基于熵权法的TOPSIS模型

视频课地址&#xff1a;https://www.bilibili.com/video/BV1eRyVYUEhg 本系列文章和课程一样&#xff0c;只使用Python实现&#xff0c;好久没玩数学建模了 国赛中不能再用TOPSIS&#xff0c;可以做辅助算法。 1. 算法原理 熵权TOPSIS方法是一种结合熵权法和TOPSIS的决策分析…

当今世界如何减少暴戾之气和矛盾纷争

《消暴戾、减纷争》&#xff08;一&#xff09; 暴戾之气常见于陌生人之间、纷争矛盾常见于与陌生人、同事、朋友、家人之间&#xff0c;总之就是一切人际关系、交际 常见案例&#xff1a;路怒症、住户与外卖小哥的纷争&#xff0c;同事、朋友、家人之间的矛盾 小吵还好&#…

【情感】程序人生之情感关系中的平等意识(如何经营一段长期稳定的关系 沸羊羊舔狗自查表)

【情感】程序人生之情感关系中的平等意识&#xff08;如何经营一段长期稳定的关系 & 沸羊羊舔狗自查表&#xff09; 文章目录 1、情感关系中的平等意识2、如何经营一段长期稳定的关系&#xff08;避免左倾 | 敬畏与担当&#xff09;3、沸羊羊/舔狗自查表&#xff08;避免右…

让css设置的更具有合理性

目录 一、合理性设置宽高 二、避免重叠情况&#xff0c;不要只设置最大宽 三、优先使用弹性布局特性 四、单词、数字换行处理 五、其他编码建议 平常写css时&#xff0c;除了遵循一些 顺序、简化、命名上的规范&#xff0c;让css具有合理性也是重要的一环。 最近的需求场…

Go小技巧易错点100例(二十一)

本篇内容&#xff1a; errors.Is方法与两种方式进行error比较 在Go语言中&#xff0c;处理错误&#xff08;error 类型&#xff09;时&#xff0c;errors.Is 和直接使用 操作符进行错误比较&#xff0c;虽然看起来都用于比较错误&#xff0c;但实际上它们有着根本的不同。这主…

【服务器项目部署】✈️将本地项目部署到服务器(二)!

目录 &#x1f44b;前言 &#x1f440;一、功能调整 &#x1f331;二、服务部署 &#x1f49e;️三、代码调整 &#x1f37b;四、章末 &#x1f44b;前言 小伙伴们大家好&#xff0c;上篇文章本地实践了如何将本地项目部署到服务器上&#xff0c;从服务器的选择、服务器环境…

Kafka消息队列

目录 前置内容常用脚本说明和示例描述与定义部分术语说明两种模式点对点模式发布订阅模式 topic主题命令行操作指令生产者Broker消费者 前置内容 队列&#xff1a; 先进先出 应用&#xff1a; 大数据中主要用于离线和实时处理 流程&#xff1a; Flume正常获取数据&#xff0c;…

如何使用 Ansys OptiSlang 同时运行多个参数化设计研究

了解如何通过使用 OptiSLang 同时运行多个参数化设计研究来提高工作效率。 了解参数化设计研究的重要性 参数化设计研究在工程和设计过程中起着至关重要的作用。通过改变输入参数&#xff0c;工程师可以探索不同设计选择的效果&#xff0c;并优化其设计以满足性能、成本或其他…

Nginx (40分钟学会,快速入门)

一、什么是Nginx ? 可以做什么 &#xff1f; Nginx 是高性能的 HTTP 和反向代理的 web 服务器&#xff0c;处理高并发能力是十分强大的&#xff0c;能经受高负载的考验&#xff0c;有报告表明能支持高达50000个并发的连接数.Nginx特点就是内存少&#xff0c;并发能力强。事实上…

【Rust自学】10.6. 生命周期 Pt.2:生命周期的语法与例子

喜欢的话别忘了点赞、收藏加关注哦&#xff0c;对接下来的教程有兴趣的可以关注专栏。谢谢喵&#xff01;(&#xff65;ω&#xff65;) 10.6.1. 生命周期标注语法 生命周期的标注并不会改变引用的生命周期长度。如果某个函数它制定了泛型生命周期参数&#xff0c;那么它就可…

【Android项目学习】3. MVVMHabit

项目链接 文章目录 一. 项目结构1. 项目整体划分2. 模块细分 二. Android知识点学习1. registerActivityLifecycleCallbacks方法2. 一. 项目结构 1. 项目整体划分 MVVMHabit是以谷歌DataBindingLiveDataViewModel框架为基础&#xff0c;整合OkhttpRxJavaRetrofitGlide等流行…

【大模型】7 天 AI 大模型学习

7 天 AI 大模型学习 Day 3 今天&#xff0c;我们要一起学习大模型微调了 &#xff5e; 包括&#xff1a;大模型微调领域概览、Lora微调 等 &#xff5e; 文章目录 7 天 AI 大模型学习 Day 3大模型微调概览大模型项目 pipeline提示词工程 Prompt EngineeringIn-context Learning…