【Go系列】 Go的高并发模式

承上启下

        我们在之前已经学习了goroutine和channel的并发模式,也学会了sync库和context的控制。那么在Go里面一般都会使用哪些高并发模式呢?今天让我们在这篇文章中一起揭晓一下。

开始学习

for ... select...模式

for select模式是Go语言中处理并发的一种常见模式,它结合了for循环和select语句来处理多个channel上的通信。这种模式通常用于以下场景:

  • 同时从多个channel接收数据。
  • 在一个循环中处理多个channel上的消息,直到满足某个条件(例如接收到一个特殊的消息或达到某个截止时间)。

下面是for select模式的基本结构和用法:

基本结构
for {select {case <-ch1:// 处理从ch1接收到的数据case data := <-ch2:// 处理从ch2接收到的数据case ch3 <- data:// 向ch3发送数据default:// 当没有其他case准备就绪时执行}// 可能还有其他逻辑// 可以在这里检查是否应该退出循环
}

用法说明

  • 接收数据:在selectcase子句中,你可以从多个channel接收数据。当任何一个channel准备好发送数据时,相应的case就会被执行。

  • 发送数据:你也可以在selectcase子句中向channel发送数据。如果channel准备好接收数据,则case会被执行。

  • 默认情况default子句是可选的。如果没有channel准备好通信,并且提供了default子句,则default会被执行。这可以用来防止select无限期地阻塞,如果所有channel都没有准备好。

  • 退出循环:通常在for循环内部,你需要检查某些条件以决定是否应该退出循环。这可以通过设置一个标志、使用context包来处理取消信号,或者在接收到特定消息时完成。

select .. timeout

select timeout模式是Go语言中处理并发时的一种常见模式,它通过在select语句中包含一个超时情况来防止goroutine无限期地等待channel操作。这种模式对于避免goroutine因等待某些可能永远不会发生的事件而永久阻塞非常有用。

基本结构

下面是select timeout模式的基本结构:

select {
case <-ch:// 当从ch接收到数据时执行// 处理接收到的数据
case <-time.After(timeoutDuration):// 当超时时间到达时执行// 处理超时情况
}

用法说明

  • channel操作select的第一个case是正常的channel操作,可以是接收或发送数据。

  • 超时操作:第二个case使用了time.After函数,它返回一个在指定的持续时间timeoutDuration后发送当前时间的channel。当这个case被选中时,意味着已经超过了指定的超时时间。

  • 处理超时:当超时发生时,你可以执行一些清理工作、设置错误状态、重试操作或者直接退出goroutine。

示例

以下是一个使用select timeout模式的示例,它展示了如何在等待一个channel操作时设置超时:

package mainimport ("fmt""time"
)func main() {ch := make(chan int)timeoutDuration := 2 * time.Second// 启动一个goroutine来模拟一个可能延迟的操作go func() {time.Sleep(3 * time.Second) // 模拟耗时操作ch <- 42 // 发送数据}()// 使用select timeout模式等待channel操作或超时select {case data := <-ch:fmt.Println("Received data:", data)case <-time.After(timeoutDuration):fmt.Println("Operation timed out")}fmt.Println("Done.")
}

在这个示例中,我们创建了一个channel ch 和一个超时时间 timeoutDuration。然后,我们启动一个goroutine来模拟一个耗时操作,该操作在3秒后向channel发送一个值。主goroutine使用select timeout模式来等待从channel接收数据或超时。由于我们设置的超时时间为2秒,而goroutine需要3秒来发送数据,因此会触发超时case

运行这个程序,你会看到输出:

Operation timed out
Done.

这个模式确保了即使channel操作没有在预期的时间内完成,程序也不会无限期地等待,而是可以采取适当的超时处理措施。

Pipeline模式

Pipeline模式在Go语言中是一种处理数据流的高效并发模式,它通过将数据处理任务分解成一系列的阶段(stages),每个阶段由一组goroutine组成,这些goroutine之间通过channel连接。这种模式类似于工厂流水线,每个工人(goroutine)负责一部分工作,然后将半成品传递给下一个工人。

基本结构

Pipeline模式通常包含以下三个主要部分:

  1. 生成器(Generator):负责生成数据,通常是一个或多个goroutine,它们将数据发送到channel。

  2. 处理器(Processor):负责处理数据,可以是多个goroutine,每个goroutine从输入channel接收数据,处理完毕后发送到输出channel。

  3. 汇聚器(Collector):负责收集最终结果,通常是一个或多个goroutine,它们从channel接收数据并执行最终的聚合操作。

以下是一个基本的Pipeline模式的示例:

package mainimport "fmt"// Generator: 生成0到9的数字
func generate(nums ...int) <-chan int {out := make(chan int)go func() {for _, n := range nums {out <- n}close(out)}()return out
}// Processor: 将输入的数字乘以2
func multiply(in <-chan int) <-chan int {out := make(chan int)go func() {for n := range in {out <- n * 2}close(out)}()return out
}// Collector: 打印结果
func print(in <-chan int) {for n := range in {fmt.Println(n)}
}func main() {// 创建Pipelinec := generate(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)out := multiply(c)print(out)
}

在这个例子中,generate函数是一个生成器,它创建了一个goroutine来发送一系列数字。multiply函数是一个处理器,它创建了一个goroutine来接收这些数字,将它们乘以2,然后发送到另一个channel。最后,print函数作为汇聚器,它接收处理过的数字并打印它们。

特点

  • 并行性:每个阶段可以并行处理数据,这提高了程序的并发性能。

  • 解耦:每个阶段只关注自己的任务,并通过channel与其他阶段通信,降低了组件间的耦合。

  • 灵活性:可以很容易地向Pipeline中添加或移除阶段,只需确保每个阶段的输入输出channel匹配。

  • 可扩展性:可以通过增加更多的goroutine来扩展Pipeline的每个阶段,以处理更大的数据量。

Pipeline模式在Go语言中非常流行,因为它可以充分利用Go的并发特性来构建高效的数据处理流程。它适用于多种场景,如数据流处理、日志分析、图像处理等。

扇入和扇出模式

扇入(Fan-in)模式

扇入模式是指将多个子任务的结果汇总到一个channel中。在Go语言中,这通常是通过让多个goroutine将结果发送到同一个channel来实现的。

基本结构
func processTask(task Task, results chan<- Result) {// 处理任务并将结果发送到channelresult := Result{}// ... 计算结果 ...results <- result
}func fanIn(tasks []Task) []Result {numTasks := len(tasks)results := make(chan Result, numTasks) // 带缓冲的channelvar wg sync.WaitGroupfor _, task := range tasks {wg.Add(1)go func(t Task) {defer wg.Done()processTask(t, results)}(task)}wg.Wait()close(results)var resultsSlice []Resultfor result := range results {resultsSlice = append(resultsSlice, result)}return resultsSlice
}
使用说明
  • 结果收集:每个工作goroutine将处理结果发送到同一个channel。
  • 缓冲channel:使用带缓冲的channel来减少发送操作的阻塞。
  • 结果汇总:在所有工作goroutine完成后,关闭channel并从channel中读取所有结果。

在实际应用中,扇入和扇出模式通常结合使用。首先,使用扇出模式并行处理多个任务,然后使用扇入模式收集这些任务的结果。

示例

以下是一个结合使用扇入和扇出模式的示例:

package mainimport ("fmt""sync"
)// 假设Task和Result是定义好的类型
type Task int
type Result intfunc processTask(task Task, results chan<- Result) {// 模拟任务处理result := Result(task * 2)results <- result
}func fanOutFanIn(tasks []Task) []Result {numTasks := len(tasks)results := make(chan Result, numTasks)var wg sync.WaitGroupfor _, task := range tasks {wg.Add(1)go func(t Task) {defer wg.Done()processTask(t, results)}(task)}wg.Wait()close(results)var resultsSlice []Resultfor result := range results {resultsSlice = append(resultsSlice, result)}return resultsSlice
}func main() {tasks := []Task{1, 2, 3, 4, 5}results := fanOutFanIn(tasks)fmt.Println(results)
}

在这个例子中,fanOutFanIn函数首先使用扇出模式将任务分配给多个goroutine,然后使用扇入模式收集这些goroutine的结果。每个goroutine将处理结果发送到同一个channel,主goroutine等待所有goroutine完成后关闭channel,并从channel中读取所有结果。

Futures模式

Future模式是一种并发编程模式,它允许程序在等待某个操作完成的同时继续执行其他任务。在Future模式中,一个操作(通常是耗时的)被提交执行,并立即返回一个future对象,这个对象代表了操作的结果。其他部分的程序可以继续执行,而不必等待操作完成。当需要操作的结果时,程序可以检查future对象,如果操作已完成,则直接获取结果;如果操作尚未完成,则可以阻塞等待结果。

在Go语言中,Future模式可以通过以下方式实现:

使用Channel实现Future模式

在Go中,channel经常被用来实现Future模式。以下是一个简单的例子:

package mainimport ("fmt""time"
)// AsyncFunction 启动一个goroutine来执行一个耗时的操作,并返回一个channel用于获取结果
func AsyncFunction() <-chan int {resultChan := make(chan int)go func() {// 模拟耗时操作time.Sleep(2 * time.Second)resultChan <- 42 // 将结果发送到channel}()return resultChan
}func main() {// 调用AsyncFunction,它立即返回一个channelfuture := AsyncFunction()// 在等待结果的同时,可以执行其他操作fmt.Println("Do some other work...")// 当需要结果时,从channel读取result := <-futurefmt.Printf("The result is: %d\n", result)
}

在上面的代码中,AsyncFunction函数启动了一个goroutine来执行一个耗时的操作,并返回一个channel。主goroutine可以在等待结果的同时执行其他任务。当需要结果时,它从channel中读取。

使用sync包实现Future模式

Go语言的sync包提供了一个sync.WaitGroup类型,可以用来等待一组操作完成。虽然它不直接提供future对象,但可以用来实现类似的功能。

package mainimport ("fmt""sync""time"
)// DoWork 启动一个goroutine来执行一个耗时的操作,并通过WaitGroup等待其完成
func DoWork(wg *sync.WaitGroup, result *int) {defer wg.Done()// 模拟耗时操作time.Sleep(2 * time.Second)*result = 42 // 设置结果
}func main() {var wg sync.WaitGroupvar result intwg.Add(1) // 增加WaitGroup的计数go DoWork(&wg, &result) // 启动goroutine// 在等待结果的同时,可以执行其他操作fmt.Println("Do some other work...")wg.Wait() // 等待goroutine完成fmt.Printf("The result is: %d\n", result)
}

在这个例子中,DoWork函数在一个新的goroutine中执行耗时的操作,并通过指针参数返回结果。sync.WaitGroup用于等待goroutine完成。在DoWork执行的同时,主goroutine可以执行其他任务。当WaitGroup.Wait()被调用时,主goroutine会阻塞,直到DoWork完成。

这两种方法都可以在Go中实现Future模式,让你能够编写更高效的并发程序。使用Future模式,你可以有效地利用并发性,避免不必要的等待,从而提高程序的响应性和吞吐量。

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

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

相关文章

tomcat如何进行调优?

从两个方面考虑&#xff1a;内存和线程 首先启动Tomcat&#xff0c;实际上就是启动了一个JVM&#xff0c;所以可以按JVM调优的方式来进行调整&#xff0c;从而达到Tomcat优化的目的。 另外Tomcat中设计了一些缓存区&#xff0c;比如appReadBufSize、bufferPoolSize等缓存区来提…

设计模式使用场景实现示例及优缺点(结构型模式——享元模式)

国度的东南角&#xff0c;有一个被称为“享元村”的小村庄。村里的居民都是非常聪明的软件设计师&#xff0c;他们擅长用一种叫做“享元模式”的技术来解决内存使用问题。享元模式的核心思想是共享&#xff1a;通过共享来支持大量的细粒度对象的使用&#xff0c;从而在不牺牲程…

C# 设计一个可变长度的数据通信协议编码和解码代码。

设计一个可变长度的数据通信协议编码和解码代码。 要有本机ID字段&#xff0c;远端设备ID字段&#xff0c;指令类型字段&#xff0c;数据体字段&#xff0c;校验字段。其中一个要求是&#xff0c;每次固定收发八个字节&#xff0c;单个数据帧超过八个字节需要分包收发。对接收的…

超详细信息收集篇

1 域名信息收集 1.1 域名是什么 域名&#xff08;英语&#xff1a;Domain Name&#xff09;&#xff0c;又称网域&#xff0c;是由一串用点分隔的名字组成的 Internet 上某一台 计算机 或计算机组的名称&#xff0c;用于在数据传输时对计算机的定位标识&#xff08;有时也指地…

数据结构——栈和队列(C语言实现)

写在前面&#xff1a; 栈和队列是两种重要的线性结构。其也属于线性表&#xff0c;只是操作受限&#xff0c;本节主要讨论的是栈和队列的定义、表示方法以及C语言实现。 一、栈和队列的定义与特点 栈&#xff1a;是限定仅在表尾进行插入和删除的线性表。对栈来说&#xff0c;表…

【经验分享】关于静态分析工具排查 Bug 的方法

文章目录 编译器的静态分析cppcheck安装 cppcheck运行 cppcheck 程序员的日常工作&#xff0c;不是摸鱼扯皮&#xff0c;就是在写 Bug。虽然这是一个梗&#xff0c;但也可以看出&#xff0c;程序员的日常一定绕不开 Bug。而花更少的时间修复软件中的 Bug&#xff0c;且不引入新…

C#自定义异常(Exception)的实现

1、自定义异常类 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;namespace ExceptionApp {public class CustomException:Exception{//默认构造函数public CustomException():base() { }//接收错误信…

leetcode hot 100 刷题记录(medium)

题目3&#xff1a;无重复字符的最长子串&#xff08;YES&#xff09; 解题思路&#xff1a;其实最好想到的方法就是使用两层for,让每个字符都可以是子串的首字符&#xff0c;查看哪个子串的长度最长即可。 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长 子…

lightgbm

lightGBM 1.sklearn 使用代码 【机器学习基础】XGBoost、LightGBM与CatBoost算法对比与调参 首先&#xff0c;XGBoost、LightGBM和CatBoost都是目前经典的SOTA&#xff08;state of the art&#xff09;Boosting算法&#xff0c;都可以归类到梯度提升决策树算法系列。三个模…

探索LangChain的单元测试世界:主流框架全解析

探索LangChain的单元测试世界&#xff1a;主流框架全解析 引言 在软件开发过程中&#xff0c;单元测试是确保代码质量的关键环节。LangChain作为一个多语言编程工具链&#xff0c;支持多种编程语言&#xff0c;每种语言都有其对应的单元测试框架。本文将详细介绍LangChain支持…

5. JavaSE ——【适合小白的数组练习题】

&#x1f4d6;开场白 亲爱的读者&#xff0c;大家好&#xff01;我是一名正在学习编程的高校生。在这个博客里&#xff0c;我将和大家一起探讨编程技巧、分享实用工具&#xff0c;并交流学习心得。希望通过我的博客&#xff0c;你能学到有用的知识&#xff0c;提高自己的技能&a…

【区块链 + 智慧政务】澳门:智慧城市建设之证书电子化项目 | FISCO BCOS应用案例

2019 年 2 月 27 日&#xff0c;澳门政府设立的澳门科学技术发展基金与微众银行达成合作&#xff0c;通过区块链、人工智能、大数据、 云计算等创新技术&#xff0c;共同推进澳门特区的智慧城市建设与未来型城市发展&#xff0c;提升粤港澳大湾区的科创能力。在澳 门智慧城市建…

【数学建模】高温作业专用服装设计(2018A)隐式差分推导

为方便计算&#xff0c;对区域进行离散化处理&#xff0c;采用隐式差分格式进行离散计算。隐式差分格式如图&#xff1a; 每层材料内部 对第 j j j层材料: 其中&#xff0c; λ j \lambda_j λj​表示第 j j j层的热扩散率&#xff0c; c j c_j cj​表示第 j j j层的比热容…

Matplotlib库学习之pyplot.figure()函数

Matplotlib库学习之pyplot.figure()函数 一、简介 pyplot.figure() 是 Matplotlib 的 pyplot 模块中的一个函数&#xff0c;用于创建一个新的图形&#xff08;figure&#xff09;。在 Matplotlib 中&#xff0c;图形是绘图元素的容器&#xff0c;可以包含多个坐标轴&#xff…

linux需要熟悉的命令理解记忆

(1)光标插入 (1)一般模式下: i 插入到光标前方 记忆方法:在一般模式下, 光标选中字符, 我们按下 i, 就会插入光标的前方, insert, 表示插队 (2)一般模式下: a 插入到光标后方 记忆方法: 在一般模式下, 光标选中字符,a表示append, 添加或者附加的意思 (3) 如果要在行首或者行…

css实现每个小盒子占32%,超出就换行

代码 <div class"visitors"><visitor class"item" v-for"(user,index) in userArr" :key"user.id" :user"user" :index"index"></visitor></div><style lang"scss" scoped&…

java乱码问题

文章目录 1.eclipse所有修改编码的地方2.io读取文件乱码问题1.读写统一2.转换字符编码&#xff1a; 3.http请求返回乱码 1.eclipse所有修改编码的地方 2.io读取文件乱码问题 1.读写统一 如果文件是以UTF-8编码保存的&#xff0c;那么在读取文件时也应使用UTF-8编码。 2.转换…

Apple Vision Pro 和其商业未来

机器人、人工智能相关领域 news/events &#xff08;专栏目录&#xff09; 本文目录 一、Vision Pro 生态系统二、Apple Vision Pro 的营销用例 随着苹果公司备受期待的进军可穿戴计算领域&#xff0c;新款 Apple Vision Pro 承载着巨大的期望。 苹果公司推出的 Vision Pro 售…

百分点科技签约潍坊市数据产业发展战略合作

近日&#xff0c;潍坊市数据产业发展战略合作签约仪式举行&#xff0c;潍坊市人民政府副市长张震生&#xff0c;潍坊市财政局党组书记、局长王金祥&#xff0c;潍坊市大数据局党组书记陈强出席大会并致辞。百分点科技受邀进行战略合作签约&#xff0c;共同见证潍坊市数据要素市…

生成式人工智能(AI)的未来

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…