Go 并发编程深度指南
Go 并发编程深度指南
Go 语言以其内置的并发原语而闻名,通过 goroutine 和 channel 提供了一种高效、安全的并发编程模型。本文将全面解析 Go 的并发机制及其实际应用。
核心概念:Goroutines 和 Channels
1. Goroutines (协程)
Go 的轻量级线程实现,开销极小:
func main() {// 启动一个协程go func() {fmt.Println("Hello from goroutine!")}()// 让主程序等待一会儿time.Sleep(100 * time.Millisecond)
}
2. Channels (通道)
协程间通信的主要方式:
func main() {// 创建无缓冲通道ch := make(chan string)go func() {time.Sleep(500 * time.Millisecond)ch <- "message"}()// 阻塞等待消息msg := <-chfmt.Println("Received:", msg)
}
并发模式与最佳实践
1. WaitGroup 控制协程组
func processTasks(tasks []string) {var wg sync.WaitGroupfor i, task := range tasks {wg.Add(1) // 增加计数go func(task string, id int) {defer wg.Done() // 结束时减少计数processTask(task, id)}(task, i)}wg.Wait() // 等待所有完成fmt.Println("All tasks completed")
}
2. Worker Pool 模式
func worker(id int, jobs <-chan int, results chan<- int) {for j := range jobs {fmt.Printf("Worker %d started job %d\n", id, j)time.Sleep(time.Second)fmt.Printf("Worker %d finished job %d\n", id, j)results <- j * 2}
}func main() {jobs := make(chan int, 100)results := make(chan int, 100)// 启动3个workerfor w := 1; w <= 3; w++ {go worker(w, jobs, results)}// 发送9个任务for j := 1; j <= 9; j++ {jobs <- j}close(jobs)// 接收结果for a := 1; a <= 9; a++ {<-results}
}
3. Select 多路复用
func main() {ch1 := make(chan string)ch2 := make(chan string)go func() {time.Sleep(1 * time.Second)ch1 <- "One"}()go func() {time.Sleep(2 * time.Second)ch2 <- "Two"}()// 同时等待两个通道for i := 0; i < 2; i++ {select {case msg1 := <-ch1:fmt.Println("Received", msg1)case msg2 := <-ch2:fmt.Println("Received", msg2)}}
}
4. Context 控制协程生命周期
func worker(ctx context.Context) {for {select {case <-ctx.Done():fmt.Println("Worker canceled")returncase <-time.After(500 * time.Millisecond):fmt.Println("Working...")}}
}func main() {ctx, cancel := context.WithCancel(context.Background())go worker(ctx)// 运行3秒后取消time.Sleep(3 * time.Second)cancel()// 给worker时间响应取消time.Sleep(500 * time.Millisecond)
}
5. Mutex 保护共享资源
type SafeCounter struct {mu sync.Mutexv int
}func (c *SafeCounter) Inc() {c.mu.Lock()defer c.mu.Unlock()c.v++
}func (c *SafeCounter) Value() int {c.mu.Lock()defer c.mu.Unlock()return c.v
}func main() {counter := SafeCounter{}var wg sync.WaitGroupfor i := 0; i < 1000; i++ {wg.Add(1)go func() {defer wg.Done()counter.Inc()}()}wg.Wait()fmt.Println("Final count:", counter.Value())
}
高级并发模式
1. 扇入/扇出 (Fan-in/Fan-out)
// 生产者
func producer(done <-chan struct{}, nums ...int) <-chan int {out := make(chan int)go func() {defer close(out)for _, n := range nums {select {case out <- n:case <-done:return}}}()return out
}// 消费者
func consumer(done <-chan struct{}, in <-chan int, id int) <-chan int {out := make(chan int)go func() {defer close(out)for n := range in {// 模拟处理result := n * nselect {case out <- result:case <-done:return}}}()return out
}// 扇入多个通道
func fanIn(done <-chan struct{}, chs ...<-chan int) <-chan int {var wg sync.WaitGroupout := make(chan int)// 定义输出函数output := func(c <-chan int) {defer wg.Done()for n := range c {select {case out <- n:case <-done:return}}}wg.Add(len(chs))for _, c := range chs {go output(c)}// 启动goroutine等待所有完成go func() {wg.Wait()close(out)}()return out
}func main() {done := make(chan struct{})defer close(done)// 创建输入通道in := producer(done, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)// 启动3个消费者c1 := consumer(done, in, 1)c2 := consumer(done, in, 2)c3 := consumer(done, in, 3)// 合并结果for result := range fanIn(done, c1, c2, c3) {fmt.Println("Result:", result)}
}
2. Future/Promise 模式
func futureWork(input int) <-chan int {result := make(chan int)go func() {// 模拟耗时操作time.Sleep(500 * time.Millisecond)result <- input * 2close(result)}()return result
}func main() {f1 := futureWork(5)f2 := futureWork(10)// 并行执行后获取结果r1 := <-f1r2 := <-f2fmt.Println("Results:", r1, r2) // 10, 20
}
性能优化与陷阱规避
1. 限制并发数
func controlledWork(workers int) {sem := make(chan struct{}, workers)var wg sync.WaitGroupfor i := 0; i < 100; i++ {wg.Add(1)go func(id int) {defer wg.Done()sem <- struct{}{} // 获取信号量defer func() { <-sem }() // 释放信号量// 执行工作fmt.Printf("Worker %d starting\n", id)time.Sleep(time.Second)fmt.Printf("Worker %d done\n", id)}(i)}wg.Wait()
}
2. 通道选择与超时
func fetchData(url string, timeout time.Duration) (string, error) {ch := make(chan string, 1)go func() {// 模拟网络请求time.Sleep(500 * time.Millisecond)ch <- "Response from " + url}()select {case res := <-ch:return res, nilcase <-time.After(timeout):return "", errors.New("request timed out")}
}
3. 避免竞态条件
// 坏: 共享变量无保护
var count int
for i := 0; i < 100; i++ {go func() {count++ // 数据竞争!}()
}// 好: 使用互斥锁
var (mu sync.Mutexcount int
)
for i := 0; i < 100; i++ {go func() {mu.Lock()defer mu.Unlock()count++}()
}// 更好: 使用通道通信
ch := make(chan struct{})
go func() {count := 0for range ch {count++}
}()
for i := 0; i < 100; i++ {ch <- struct{}{}
}
并发性能分析工具
-
Race Detector:
go run -race yourprogram.go
-
pprof:
import _ "net/http/pprof"func main() {go func() {log.Println(http.ListenAndServe("localhost:6060", nil))}()// 程序主体... }
然后使用
go tool pprof http://localhost:6060/debug/pprof/profile
进行分析 -
Benchmark:
func BenchmarkWork(b *testing.B) {for i := 0; i < b.N; i++ {doWork()} }
Go 并发设计哲学
- 不要通过共享内存来通信,而应通过通信来共享内存
- 并发不是并行 - 并发是设计结构,并行是执行方式
- 利用组合而不是继承 - 通过组合小的并发原语构建复杂系统
- 错误处理也是控制流 - 将错误作为值传递,通过通道处理
Go 的并发模型提供了强大而简单的工具集,使开发者能够构建高效、可伸缩的并发系统。通过理解 goroutine、channel 和各种同步原语的使用方法,开发者可以避免许多并发编程的常见陷阱,创建出更加稳健的系统。
相关文章:
Go 并发编程深度指南
Go 并发编程深度指南 Go 语言以其内置的并发原语而闻名,通过 goroutine 和 channel 提供了一种高效、安全的并发编程模型。本文将全面解析 Go 的并发机制及其实际应用。 核心概念:Goroutines 和 Channels 1. Goroutines (协程) Go 的轻量级线程实现&…...
PostgreSQL 的扩展pg_freespacemap
PostgreSQL 的扩展pg_freespacemap pg_freespacemap 是 PostgreSQL 提供的一个内置扩展,用于查看表的空闲空间映射(Free Space Map, FSM)信息。这个扩展对于数据库性能调优和空间管理非常有用。 一 扩展概述 功能:提供对表的空…...

【Linux】进程的基本概念
目录 概念描述进程-PCB如何查看进程通过系统目录进行查看通过ps指令进行查看 通过系统调用获取进程的PID和PPID(进程标⽰符)通过系统调用创建子进程通过一段代码来介绍fork为什么要有子进程?fork为什么给子进程返回0,给父进程返回子进程的PIDfork函数到底…...

设备驱动与文件系统:05 文件使用磁盘的实现
从文件使用磁盘的实现逻辑分享 我们现在讲第30讲,内容是文件使用磁盘的具体实现,也就是相关代码是如何编写的。上一节我们探讨了如何从字符流位置算出盘块号,这是文件操作磁盘的核心。而这节课,我们将深入研究实现这一核心功能的…...

AI数据分析在体育中的应用:技术与实践
在现代体育竞技领域,"数据驱动"已不再是一个遥远的概念。尤其随着人工智能(AI)和大数据分析的不断成熟,从职业俱乐部到赛事直播平台,从运动员训练到球迷观赛体验,AI正以前所未有的方式渗透并改变…...

zabbix 6 监控 docker 容器
zabbix 6 监控 docker 容器 1.安装zabbix_agent2 curl -s http://10.26.211.56:8080/centos7-agent2-install.sh | bash2.在zabbix server 端测试 zabbix_get -s 10.26.219.180 -k docker.infoZBX_NOTSUPPORTED: Cannot fetch data: Get "http://1.28/info": dial…...

正则持续学习呀
源匹配为 (.*): (.*)$ 替换匹配为 "$1": "$2", 可将headers改为字典 参考 【爬虫军火库】如何优雅地复制请求头 - 知乎...
【Go语言基础【19】】接口:灵活实现多态的核心机制
文章目录 零、概述一、接口基础1、接口的基本概念a. 接口定义b. 类型实现接口(无需显式声明)c. 接口变量(体现了多态) 2、实现接口的方式3、接口组合4、接口的底层结构 二、空接口与类型断言1. 空接口(interface{}&…...
MySql读写分离部署(一主一从,双主双从,Mycat)
参考资料: 参考视频 参考博客 视频参考资料及安装包: https://pan.baidu.com/s/1xT_WokN_xlRv0h06b6F3yg 提取码: aag3 Mysql主从复制部署指南(一主一从) NotePad++编辑Linux服务器文档 Mysql高版本(8.0及以后)Linux安装 Mysql分库分表(基于Mycat)的基本部署 …...

Go基本语法——go语言中的四种变量定义方法
前言 在go语言中,定义一个变量有四种方式,本文单从语法的层面来介绍这几种方式 单变量定义方法 1.var 变量名 类型,不进行初始化 例如,定义一个变量a后为其赋值,并且打印其值,运行结果如下 //1.不进行…...

27.【新型数据架构】-数据共享架构
27.【新型数据架构】-数据共享架构:降低数据获取成本,实时数据访问,保持数据新鲜度,促进数据经济发展,打破数据孤岛,标准化数据交换,增强数据安全性,完整审计追踪,合规性保障 一、数据共享架构的本质:打破壁垒的“数字立交桥” 传统企业或组织间的数据往往呈现“烟囱…...

virtualbox 如何虚拟机ip固定
1、在网络管理里新建 2、配置网络 3、 进入linux系统,查看 查看 网卡是enp0s8, ifconfig 4、进入网卡配置文件 cd /etc/sysconfig/network-scripts如果没有enp0s8 ,则使用mv ifcfg-enp0s3 ifcfg-enp0s8命令 配置项如下 TYPEEthernet PROXY_METHODn…...

RKNN3588上部署 RTDETRV2
RT-DETR V2 是由百度研究团队在 2024年 提出的,是其广受好评的实时目标检测模型 RT-DETR 的重大升级版本。它继承了第一代 RT-DETR 利用 Transformer 架构实现端到端目标检测 和 卓越实时性能 的核心优势,并针对模型精度、训练效率和部署灵活性进行了全方…...

Python----循环神经网络(BiLSTM:双向长短时记忆网络)
一、LSTM 与 BiLSTM对比 1.1、LSTM LSTM(长短期记忆网络) 是一种改进的循环神经网络(RNN),专门解决传统RNN难以学习长期依赖的问题。它通过遗忘门、输入门和输出门来控制信息的流动,保留重要信息并丢弃无关…...
Elasticsearch 常用操作命令整合 (cURL 版本)
Elasticsearch 常用操作命令整合 (cURL 版本) 集群管理 查看集群健康状态 curl -X GET "localhost:9200/_cluster/health?pretty"查看节点信息 curl -X GET "localhost:9200/_cat/nodes?v"查看集群统计信息 curl -X GET "localhost:9200/_clus…...
Redis持久化策略:RDB与AOF详解
目录 1. RDB持久化工作原理触发机制优点缺点配置示例 2. AOF持久化工作原理同步策略重写机制优点缺点配置示例 3. RDB与AOF比较4. 混合持久化(Redis 4.0)5. 选择建议 Redis提供了两种主要的持久化机制来保证数据安全:RDB(Redis Database)和AOF(Append Only File)。本…...

Linux系统编程-DAY10(TCP操作)
一、网络模型 1、服务器/客户端模型 (1)C/S:client server (2)B/S:browser server (3)P2P:peer to peer 2、C/S与B/S区别 (1)客户端不同&#…...

GPU虚拟化
引言 现有如下环境(注意相关配置:只有一个k8s节点,且该节点上只有一张GPU卡): // k8s版本 $ kubectl version Client Version: version.Info{Major:"1", Minor:"22", GitVersion:"v1.22.7&…...

LabVIEW工业级多任务实时测控系统
采用LabVIEW构建了一套适用于工业自动化领域的多任务实时测控系统。系统采用分布式架构,集成高精度数据采集、实时控制、网络通信及远程监控等功能,通过硬件与软件的深度协同,实现对工业现场多类型信号的精准测控,展现 LabVIEW 在…...
Python学习(7) ----- Python起源
🐍《Python 的诞生》:一段圣诞假期的奇妙冒险 📍时间:1989 年圣诞节 在荷兰阿姆斯特丹的一个寒冷冬夜,灯光昏黄、窗外飘着雪。一个程序员 Guido van Rossum 正窝在家里度假——没有会议、没有项目、没有 bug…...
Java中List的forEach用法详解
在 Java 中,List.forEach() 是 Java 8 引入的一种简洁的遍历集合元素的方法。它基于函数式编程思想,接受一个 Consumer 函数式接口作为参数,用于对集合中的每个元素执行操作。 基本语法 java 复制 下载 list.forEach(consumer); 使用示…...
LeetCode 1356.根据数字二进制下1的数目排序
题目: 给你一个整数数组 arr 。请你将数组中的元素按照其二进制表示中数字 1 的数目升序排序。 如果存在多个数字二进制中 1 的数目相同,则必须将它们按照数值大小升序排列。 请你返回排序后的数组。 提示: 1 < arr.length < 5000…...

破解HTTP无状态:基于Java的Session与Cookie协同工作指南
HTTP协议自身是属于“无状态”协议 无状态是指:默认情况下,HTTP协议的客户端和服务器之间的这次通信,和下次通信之间没有直接的关系 但在实际开发中,我们很多时候是需要知道请求之间的关联关系的 上述图中的令牌,通常就…...

JS 事件流机制详解:冒泡、捕获与完整事件流
JS 事件流机制详解:冒泡、捕获与完整事件流 文章目录 JS 事件流机制详解:冒泡、捕获与完整事件流一、DOM 事件流基本概念二、事件捕获 (Event Capturing)特点代码示例 三、事件冒泡 (Event Bubbling)特点代码示例 四、完整事件流示例HTML 结构JavaScript…...
MYSQL too many connection问题排查和修复
1.连接数据库 mysql -u root -p 1.1 查看mysql路径 如果没有配置mysql的环境变量,可以直接找mysql的安装目录 打开任务管理器-》服务-》Mysql(根据版本不同后面带有数字,找运行的那个) 打开服务->mysql->属性-》可执行文件的路径,…...
SpringCloudAlibaba和SpringBoot版本问题
SpringCloudAlibaba和SpringBoot版本问题 直接参考官方给出的版本说明,具体地址:https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E Spring Cloud Alibaba VersionSentinel VersionNacos VersionRocketMQ Ver…...

算法专题七:分治
快排 1.颜色分类 题目链接:75. 颜色分类 - 力扣(LeetCode) class Solution {public void swap(int[] nums, int i, int j){int t = nums[i];nums[i] = nums[j];nums[j] = t;}public void sortColors(int[] nums) {int left=-1 ,i=0 ,right=nums.length;while(i<right){i…...

Vue中虚拟DOM的原理与作用
绪论 首先我们先了解,DOM(Document Object Model,文档对象模型) 是浏览器对 HTML/XML 文档的结构化表示,它将文档解析为一个由节点(Node)和对象组成的树形结构(称为 DOM 树…...
前端十种排序算法解析
1. 冒泡排序 1.1 说明 冒泡排序为一种常用排序算法,执行过程为从数组的第一个位置开始,相邻的进行比较,将最大的数移动到数组的最后位置执行的时间复杂度与空间复杂度为 o(n^2) 1.2 执行过程 从数组的第一个位置开始,截止位置为 …...
使用 C/C++ 和 OpenCV 添加图片水印
使用 C/C 和 OpenCV 添加图片水印 🖼️ 在数字图像处理中,添加水印是一种常见的操作,可以用于版权保护、品牌宣传或信息标注。本文将介绍如何使用 C/C 和强大的计算机视觉库 OpenCV 来实现将自定义水印(图片或文字)添…...