Go并发编程实战:深入理解Goroutine与Channel

  • Go并发编程实战:深入理解Goroutine与Channel
    • 概述
    • 1. 为什么是Go的并发?从“线程”与“协程”说起
    • 2. Goroutine:如何使用?
    • 3. Channel:Goroutine间的安全通信
      • 创建与使用
      • 缓冲与同步
      • 经典模式:Range和Close
    • 4. 实战项目:构建一个并发Web爬虫
      • 核心功能
      • 代码实现
      • 如何运行
    • 5. 延伸学习与资源推荐

Go并发编程实战:深入理解Goroutine与Channel

概述

Go语言(Golang)凭借其简洁的语法、强大的标准库和原生支持的并发模型,在现代软件开发中占据了重要地位,尤其在云计算、微服务和网络服务后端领域。其最引人注目的特性莫过于GoroutineChannel,它们提供了一种轻量级、安全且高效的并发编程方式,让你能轻松构建高性能的并发程序。本文将带你从入门到实战,彻底掌握Go的并发哲学。
在这里插入图片描述

1. 为什么是Go的并发?从“线程”与“协程”说起

在传统语言(如Java)中,我们使用**线程(Thread)**来实现并发。然而,系统线程创建和上下文切换开销大,且数量有限(通常一台机器几千个),管理和同步(通过锁)也非常复杂,容易出错。

Go语言引入了**Goroutine(Go协程)**的概念。它是一种由Go运行时(runtime)管理的轻量级线程。

  • 开销极低:初始栈很小(约2KB),可以根据需要动态伸缩。你可以轻松创建数十万甚至上百万个Goroutine而耗尽内存。
  • 调度高效:Go运行时内置了一个强大的调度器(Scheduler),它在少量系统线程上复用Goroutine。当某个Goroutine发生阻塞(如I/O操作)时,调度器会立刻将其挂起,并在同一个线程上运行其他Goroutine。这一切对开发者透明,极大提高了CPU利用率。

简单来说,Goroutine让你可以用同步的方式写异步的代码,以极低的成本获得极高的并发能力。

2. Goroutine:如何使用?

使用Goroutine非常简单,只需在普通的函数调用前加上关键字 go

package mainimport ("fmt""time"
)func say(s string) {for i := 0; i < 3; i++ {time.Sleep(100 * time.Millisecond)fmt.Println(s)}
}func main() {// 在一个新的Goroutine中运行say函数go say("world")// 在主Goroutine中运行say函数say("hello")
}

运行上面的代码,你会看到"hello"和"world"交错打印,这表明两个函数在同时执行。注意:主Goroutine结束后,所有其他Goroutine会立即被终止,因此你可能需要一些同步机制来等待它们完成(如使用sync.WaitGroup)。

3. Channel:Goroutine间的安全通信

Goroutine是并发执行的,它们之间如何安全地传递数据和协调工作呢?答案是 Channel(通道)

Channel是一种类型化的管道,你可以通过它用操作符 <- 发送和接收值。

创建与使用

ch := make(chan int) // 创建一个传递int类型的通道// 在Goroutine中向通道发送数据
go func() {ch <- 42 // 将42发送到通道ch
}()// 从通道接收数据
value := <-ch
fmt.Println(value) // 输出: 42

缓冲与同步

默认通道是**无缓冲(Unbuffered)的:发送操作会一直阻塞,直到有另一个Goroutine执行接收操作,这是一种强大的同步机制。
你也可以创建
带缓冲(Buffered)**的通道:

ch := make(chan int, 2) // 缓冲区大小为2
ch <- 1
ch <- 2
// ch <- 3 // 如果此时再发送,就会阻塞,因为缓冲区满了fmt.Println(<-ch) // 1
fmt.Println(<-ch) // 2

经典模式:Range和Close

发送者可以通过close函数关闭通道,表示没有更多值会被发送。接收者可以使用range循环来持续接收值,直到通道被关闭。

func fibonacci(n int, c chan int) {x, y := 0, 1for i := 0; i < n; i++ {c <- xx, y = y, x+y}close(c) // 关闭通道
}func main() {c := make(chan int, 10)go fibonacci(cap(c), c)// 使用range循环从通道中接收数据,直到通道被关闭for i := range c {fmt.Println(i)}
}

4. 实战项目:构建一个并发Web爬虫

让我们利用所学知识,构建一个简单的、并发安全的Web爬虫。它的功能是并发地抓取一组URL,并统计每个页面的大小。

核心功能

  • 并发地发送HTTP GET请求获取多个URL的内容。
  • 使用Channel来收集结果。
  • 使用WaitGroup来等待所有抓取任务完成。

代码实现

package mainimport ("fmt""io""log""net/http""sync""time"
)// FetchResult 用于存放抓取结果
type FetchResult struct {Url  stringSize int64Err  error
}// fetchUrl 抓取单个URL,将结果发送到channel
func fetchUrl(url string, ch chan<- FetchResult, wg *sync.WaitGroup) {defer wg.Done() // 通知WaitGroup,当前Goroutine已完成start := time.Now()resp, err := http.Get(url)if err != nil {ch <- FetchResult{Url: url, Err: err}return}defer resp.Body.Close()body, err := io.ReadAll(resp.Body)if err != nil {ch <- FetchResult{Url: url, Err: err}return}elapsed := time.Since(start)size := int64(len(body))ch <- FetchResult{Url: url, Size: size, Err: nil}log.Printf("Fetched %s (%d bytes) in %s", url, size, elapsed)
}func main() {urls := []string{"https://www.google.com","https://www.github.com","https://www.stackoverflow.com","https://go.dev","https://medium.com",}// 创建一个带缓冲的Channel存放结果resultCh := make(chan FetchResult, len(urls))// 创建一个WaitGroup来等待所有Goroutine完成var wg sync.WaitGroup// 为每个URL启动一个Goroutinefor _, url := range urls {wg.Add(1) // WaitGroup计数器+1go fetchUrl(url, resultCh, &wg)}// 启动一个单独的Goroutine,等待所有抓取任务完成后关闭Channelgo func() {wg.Wait()close(resultCh)}()// 主Goroutine从Channel中读取并处理所有结果fmt.Println("\n=== Fetch Results ===")for result := range resultCh {if result.Err != nil {fmt.Printf("Failed to fetch %s: %v\n", result.Url, result.Err)} else {fmt.Printf("Fetched %s: %d bytes\n", result.Url, result.Size)}}
}

如何运行

  1. 将代码保存为 concurrent_crawler.go
  2. 在终端运行:go run concurrent_crawler.go

这个项目完美展示了如何用Goroutine实现“fork-join”并发模式,如何使用Channel进行通信,以及如何使用WaitGroup进行同步,是Go并发编程的经典范例。

5. 延伸学习与资源推荐

  • 官方资源:

    • The Go Programming Language Tour (Go语言之旅):官方交互式教程,非常适合初学者。
    • Effective Go:编写优雅、地道的Go代码的最佳实践。
  • 经典书籍:

    • 《The Go Programming Language》 (Alan A. A. Donovan & Brian W. Kernighan):被誉为Go语言的“圣经”,深度和广度俱佳。
  • 进阶主题:

    • Context包:用于在Goroutine之间传递截止时间、取消信号以及其他请求范围的值,是构建网络服务的关键。
    • Sync包:提供了基本的同步原语,如互斥锁(Mutex)、读写锁(RWMutex)等,用于更底层的同步控制。
    • 并发模式:学习select语句、超时控制、管道(Pipeline)、工作池(Worker Pool)等高级模式。

Go的并发模型是其灵魂所在。掌握Goroutine和Channel,你就能充分利用现代多核CPU的优势,轻松构建出高性能、高可靠性的服务。祝你学习愉快!

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

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

相关文章

2025服贸会“海淀之夜”,点亮“科技”与“服务”底色

2025年9月12日傍晚&#xff0c;北京颐和园&#xff0c;十七孔桥旁&#xff0c;2025年中国国际服务贸易交易会“海淀之夜”如约而至。在“海淀之夜”&#xff0c;科技机构、金融机构、咨询服务机构、出海服务企业以及跨国企业和国际友人等&#xff0c;将目光聚焦于此。被第三方机…

qt使用camke时,采用vcpkg工具链设置VTK的qt模块QVTKOpenGLNativeWidget

下载:QVTKOpenGLNativeWidget嵌入qt应用中资源-CSDN下载 1.通过vcpkg安装VTK,目前的VTK里面默认为qt6,如果需要安装qt5,需要将端口配置进行修改 笔者的vcpkg的vtk端口路径:D:\vcpkg\ports\vtk portfile.cmake 修改点: #第一处 #file(READ "${CURRENT_INSTALLED_DIR}/sh…

Axios在鸿蒙应用开发中的使用

目录一、简介二、安装与配置三、axios用法1.axios泛型参数(1).第三个泛型参数-约束data请求参数的类型(2).第二个泛型参数-决定后台返回数据的类型2.axios拦截器3.请求工具封装统一处理业务状态码错误统一处理401或404错误一、简介 Axios 是一个基于 Promise 的网络请求库&…

第九周文件上传

文件上传漏洞 不同的网站要不同的webshell。我们使用是php开发的网站。 一服务器白名单绕过 服务端白名单(Whitelist)是⼀种安全机制&#xff0c;它只允许预定义的合法元素通过&#xff08;只有有限的元素进入&#xff09;&#xff0c;其他所有内容默认被拒绝。相比黑名单&am…

计算机视觉必读论文:从经典到前沿

计算机视觉必读论文:从经典到前沿 一、前言 二、经典论文解读​ 2.1 图像分类​ 2.1.1 《ImageNet Classification with Deep Convolutional Neural Networks》(AlexNet)​ 2.1.2 《Very Deep Convolutional Networks for Large-Scale Image Recognition》(VGGNet)​ 2.1.…

对比PowerBI的字段参数,QuickBI的已选字段还有改进的空间

对比PowerBI的字段参数&#xff0c;QuickBI的已选字段还有改进的空间 之前分享过QuickBI的已选字段 vs PowerBI的字段参数&#xff0c;QuickBI可以在表格中实现PowerBI的字段参数效果&#xff0c;甚至比PowerBI实现的过程和使用方式更丝滑。 但如果应用到图形中会怎么样呢&am…

飞算JavaAI:Java开发新时代的破晓之光

免责声明&#xff1a;此文章的所有内容皆是本人实验测评&#xff0c;并非广告推广&#xff0c;并非抄袭。如有侵权&#xff0c;请联系&#xff0c;谢谢&#xff01;【#飞算JavaAl炫技赛】 【#Java开发】摘要&#xff1a;飞算JavaAI作为全球首款聚焦Java的智能开发助手&#xff…

vulntarget-c靶场内网渗透

1. 环境搭建 2.对ubuntu20的渗透 对其进行端口扫描 访问80端口 发现是laravel框架。版本是v8.78.1 使用 kaili 自带的msf 进行渗透 search laravel use exploit/multi/php/ignition_laravel_debug_rce执行利用完成检测 上传木马 先将木马进行base64编码 <?php eval($_P…

基于大模型多模态的人体体型评估:从“尺码测量”到“视觉-感受”范式

基于大模型多模态的人体体型评估&#xff1a;从“尺码测量”到“视觉-感受”范式摘要&#xff1a;传统体型识别依赖CV骨架/关键点与像素量尺&#xff0c;容易受衣物、发型、姿态、光照影响&#xff0c;且“厘米级数值”与穿衣体验、审美感受之间存在鸿沟。本文提出一种基于大模…

【docker】——docker国内可用的源

不知道哪里来的&#xff0c;但是可以用。1. 解决方案打开配置文件&#xff08;若文件不存在&#xff0c;会自动创建&#xff09; sudo vim /etc/docker/daemon.json将以下内容粘贴进去{"builder": {"gc": {"defaultKeepStorage": "20GB&quo…

【Windows端口管理】快速查看和释放被系统保留的TCP端口

问题描述在Windows系统开发时&#xff0c;经常遇到端口无法使用的问题。系统会自动保留一系列TCP/UDP端口范围&#xff0c;导致应用程序无法绑定这些端口。查看所有被保留的端口范围查看TCP保留端口# 查看所有TCP端口排除范围 netsh interface ipv4 show excludedportrange pro…

面经汇总(1)

1.介绍C面向对象的三大特性2.介绍常见的排序算法3.介绍TCP/UDP区别4.TCP三次握手四次挥手5.如果四次挥手第四次客户端的ACK没有发出去会有什么结果&#xff1f;6.介绍MYSQL的事务7.介绍线程池8.主要的线程池有哪几种&#xff1f;9.手撕反转链表10.介绍对象存储以及常见的对象存…

遥感图像数字水印系统优化方案

遥感图像数字水印系统优化方案 1. 引言 遥感图像在现代地理信息系统、环境监测、军事侦察等领域发挥着重要作用。为了保护遥感图像的版权和完整性&#xff0c;数字水印技术被广泛应用。然而&#xff0c;现有的遥感图像水印方案往往在不可见性、鲁棒性和容量之间存在权衡&#x…

鸿蒙高效数据处理框架全攻略:缓存、并行与流式实战

摘要 在如今的物联网和智能设备世界里&#xff0c;数据已经成为最关键的资源。无论是可穿戴设备、智能家居&#xff0c;还是车载系统&#xff0c;每一秒都会产生大量数据。如果缺少一套高效的数据处理框架&#xff0c;开发者就可能面临内存溢出、处理延迟大、设备卡顿等问题。本…

零售企业数字化转型的道、法、术:基于开源AI大模型AI智能名片S2B2C商城小程序的战略重构

摘要 在数字经济与消费升级的双重驱动下&#xff0c;零售企业正经历从"流量争夺"到"用户时间争夺"的范式转变。本文以阿里巴巴、京东、万达三大巨头的战略实践为样本&#xff0c;结合开源AI大模型、AI智能名片与S2B2C商城小程序的技术特性&#xff0c;提出…

瑞云渲染为电影《731》提供云渲染技术支持,助力影片全球上映

在“九一八事变”94周年这一庄严沉重的纪念时刻&#xff0c;抗战电影《731》&#xff08;海外名&#xff1a;《EVIL UNBOUND》&#xff09;于世界各地上映&#xff0c;激起广泛的社会反响与深远的历史思考。 瑞云渲染&#xff08;Renderbus&#xff09;作为全球领先的云渲染服…

EasyDSS视频直播RTMP推流技术如何实现多机型的无人机视频统一直播

在当今这个瞬息万变的传媒时代&#xff0c;无人机与推流直播的结合&#xff0c;正以前所未有的方式重塑着信息传播的边界。无人机以其独特的空中视角和灵活的机动性&#xff0c;为直播行业带来了革命性的变化&#xff0c;而推流直播技术的成熟&#xff0c;则让这一变化得以实时…

str.maketrans() 方法

str.maketrans() 方法 功能概述 str.maketrans() 是 Python 中字符串对象的一个静态方法&#xff0c;用于创建一个字符映射转换表。这个转换表本质上是一个字典&#xff0c;它定义了字符之间的替换规则&#xff0c;后续可以被 str.translate() 方法使用&#xff0c;以实现字符串…

敏感词检测API平台推荐

敏感词检测API平台推荐 背景简介 敏感词检测用于识别文本中的违规、涉政、涉黄、辱骂等敏感词&#xff0c;帮助产品在评论、弹幕、客服对话、运营文案、广告投放等环节实现自动化质检与合规拦截。市场上主要有两类服务商&#xff1a; 专业型厂商&#xff1a;聚焦算法与工程落…

Day25_【深度学习(3)—PyTorch使用(6)—张量拼接操作】

张量的拼接操作在神经网络搭建过程中是非常常用的方法&#xff0c;例如: 在后面将要学习的注意力机制中都使用到了张量拼接。torch.cat 函数可以将两个张量根据指定的维度拼接起来&#xff0c;不改变数据维度。前提&#xff1a;除了拼接的维度&#xff0c;其他维度一定要相同。…