0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

go语言如何解决并发问题

马哥Linux运维 来源:博客园snail_lie 2024-10-23 13:38 次阅读

一、选择GO的原因

作为一个后端开发,日常工作中接触最多的两门语言就是PHP和GO了。无可否认,PHP确实是最好的语言(手动狗头哈哈),写起来真的很舒爽,没有任何心智负担,字符串和整型压根就不用区分,开发速度真的是比GO快很多。现在工作中也还是有一些老项目在使用PHP,但21年之后的新项目基本上就都是用GO了。那为什么PHP那么香,还要转战使用GO呢,下面就给大家讲解一下我们新项目从PHP转GO的原因,有几个比较重要的点:

1、PHP不能满足我们的高并发业务,这是最主要的原因了,(PS:我这里所说的PHP是指官方的php-fpm模式下的开发,是一个请求一个进程的那种模式,而不是类似于swoole常驻进程的那种。那么为什么不去使用swoole呢,当然也是有的,但swoole毕竟太小众了,且之前有很多bug,使用起来心智负担太高了),而我们部门所负责的是直播业务,每天都和高并发打交道啊,所以只能将目光转向了并发小王子GO的怀抱。

2、GO语言当时在市面上很火,像腾讯、百度、滴滴、好未来这些大厂都在陆陆续续地从PHP转向GO,这也是一个讯号吧,跟着大佬们走总不会错。

3、GO语言的简单简洁,相比较于JAVA,上手是很快的(但真正学好还是没那么容易的),我当时就学了两个礼拜左右语法就跟着一起写项目了。

二、GO解决的并发问题

说到并发,是GO最基本的功能了,但是在传统的PHP中是比较困难的,如果不借助其它一些扩展的话,是做不到并发的。举个场景:每个用户进入直播间,都要获取很多信息,有版本服务信息、直播基础信息、用户信息、直播关联权益信息、直播间信息统计等等。如果是PHP的写法,就得按照下面串行的流程去做,这个接口耗时就是所有操作的时间之和,严重影响用户体验啊。

e9cda7d2-90f6-11ef-a511-92fbcf53809c.png

但如果换成GO去做这件事,那就非常清爽了,这个用户请求耗时就只需要时间最长的那个操作耗时,如下图:

e9e5d6ea-90f6-11ef-a511-92fbcf53809c.png

那么我们如何用去实现这个并发逻辑呢?

方法1:使用sync.WaitGroup

//请求入口
func main() {
var (
VersionDetail, LiveDetail, UserDetail, EquityDetail, StatisticsDetail int
)
ctx := context.Background()
GoNoErr(ctx, func() {
VersionDetail = 1 //版本服务信息
time.Sleep(1 * time.Second)
fmt.Println("执行第一个任务")
}, func() {
LiveDetail = 2 //直播基础信息
time.Sleep(2 * time.Second)
fmt.Println("执行第二个任务")
}, func() {
UserDetail = 3 //用户信息
time.Sleep(3 * time.Second)
fmt.Println("执行第三个任务")
}, func() {
EquityDetail = 4 //直播关联权益信息
time.Sleep(4 * time.Second)
fmt.Println("执行第四个任务")
}, func() {
StatisticsDetail = 5 //直播间信息统计
time.Sleep(5 * time.Second)
fmt.Println("执行第五个任务")
})
fmt.Println(VersionDetail, LiveDetail, UserDetail, EquityDetail, StatisticsDetail)
}

//并发方法
func GoNoErr(ctx context.Context, functions ...func()) {
var wg sync.WaitGroup
for _, f := range functions {
wg.Add(1)
// 每个函数启动一个协程
go func(function func()) {
function()
wg.Done()
}(f)
}
// 等待执行完
wg.Wait()
}

方法2:使用ErrGroup库

//请求入口
func main() {
var (
VersionDetail, LiveDetail, UserDetail, EquityDetail, StatisticsDetail int
err                                                                   error
)
ctx := context.Background()
err = GoErr(ctx, func() error {
VersionDetail = 1 //版本服务信息
time.Sleep(1 * time.Second)
fmt.Println("执行第一个任务")
return nil //返回实际执行的错误
}, func() error {
LiveDetail = 2 //直播基础信息
time.Sleep(2 * time.Second)
fmt.Println("执行第二个任务")
return nil //返回实际执行的错误
}, func() error {
UserDetail = 3 //用户信息
time.Sleep(3 * time.Second)
fmt.Println("执行第三个任务")
return nil //返回实际执行的错误
}, func() error {
EquityDetail = 4 //直播关联权益信息
time.Sleep(4 * time.Second)
fmt.Println("执行第四个任务")
return nil //返回实际执行的错误
}, func() error {
StatisticsDetail = 5 //直播间信息统计
time.Sleep(5 * time.Second)
fmt.Println("执行第五个任务")
return nil //返回实际执行的错误
})
if err != nil {
fmt.Println(err)
return
}
fmt.Println(VersionDetail, LiveDetail, UserDetail, EquityDetail, StatisticsDetail)

}

func GoErr(ctx context.Context, functions ...func() error) error {
var eg errgroup.Group
for i := range functions { 
f := functions[i]  //请注意这里的写法,下面有讲解
eg.Go(func() (err error) {
err = f()
if err != nil {
//记日志
}
return err
})
}
// 等待执行完
return eg.Wait()
}

上面就是使用ErrGroup库的并发执行任务的方法,可以直接拿来使用,ErrGroup这是GO官方提供的一个同步扩展库可以很好地将⼀个通⽤的⽗任务拆成⼏个⼩任务并发执⾏

上面有一点需要特别注意的写法,就是下面这段代码的写法,写法1:

for i := range functions { 
f := functions[i]  
eg.Go(func() (err error) {
err = f()

也可以这样写,写法2:

for _, f := range functions { 
fs := f  
eg.Go(func() (err error) {
err = fs()

但如果这样写就会有问题,写法3:

for _, f := range functions { 
eg.Go(func() (err error) {
err = f()

你们可以改一下,实际跑一下。会发现 (写法3) 会出现类似这样的错误结果

ea103a84-90f6-11ef-a511-92fbcf53809c.png

正确预期的结果(写法1、写法2)应该是这样的

ea234642-90f6-11ef-a511-92fbcf53809c.png

这是因为在 Go 语言中,当使用闭包(匿名函数)时,如果闭包引用了外部的变量,闭包实际上会捕获这些变量的引用。在循环中创建闭包时,如果直接将循环变量作为闭包的参数或在闭包中引用该变量,会导致所有生成的闭包都引用相同的变量,即最后一次迭代的值。

为了避免这个问题,常见的做法是在循环内部创建一个新的变量,将循环变量的值赋给这个新变量,然后在闭包中引用该新变量。这样,每次循环迭代都会创建一个新的变量,闭包捕获的是不同的变量引用,而不是相同变量的引用。

在给定的代码中,fs := f 就是为了创建一个新的变量 f,并将循环变量 f 的值赋给它。这样,在闭包中就可以安全地引用这个新变量 f,而不会受到循环迭代的影响。这个技巧非常有用,可以在循环中创建多个独立的闭包,并确保它们捕获的是预期的变量值,而不会受到循环迭代的干扰

当然,还有一些第三方库也实现了上面的并发分组操作,大家感兴趣的可以去GitHub上看看,但功能和实现基本都大同小异。以上就是GO并发的基础,将一个父任务拆分成多个子任务去执行,提高程序的并发度,节省程序耗时。我们平时在工作中,两种方法都可以直接拿来使用,可以说这两个GO并发方法几乎贯穿了我的GO职业生涯,也是最基础最实用的并发操作方法

一个人可以被毁灭,但不可以被打败。

链接:https://www.cnblogs.com/lmz-blogs/p/18200946

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 函数
    +关注

    关注

    3

    文章

    4273

    浏览量

    62290
  • 进程
    +关注

    关注

    0

    文章

    201

    浏览量

    13936
  • go语言
    +关注

    关注

    1

    文章

    157

    浏览量

    9012

原文标题:go高并发之路——go语言如何解决并发问题

文章出处:【微信号:magedu-Linux,微信公众号:马哥Linux运维】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    Go语言简介和安装方法

    Go 又称 Golang ,是 Google 的 Robert Griesemer,Rob Pike 及 Ken Thompson 开发的一种静态强类型、编译型语言Go 语言语法与
    发表于 07-19 16:33 532次阅读

    三十分钟入门基础Go Java小子版

    语法与 C 相近,但功能上有:内存安全,GC,结构形态及 CSP-style 并发计算。 适用范围 本篇文章适用于学习过其他面向对象语言(Java、Php),但没有学过Go语言的初学者
    的头像 发表于 08-12 14:32 647次阅读
    三十分钟入门基础<b class='flag-5'>Go</b> Java小子版

    Go语言开发有什么优势?怎么学?

    的方式全面的阐述Go在高并发、大流量方面的应用,课程中采用的四个项目全部来自大公司实实在在的线上案例,并不是通过简化的、阉割过的项目。可以学习到Go语言理论与应用的最佳实践,高
    发表于 12-19 16:08

    Go开发语言的优势在哪里?

    Go语言是谷歌发布的第二款开源编程语言,可以在不损失应用程序性能的情况下降低代码的复杂性,并专门针对多处理器系统应用程序的编程进行了优化,开发速度极快,可以与C或C++媲美,而且更加安全、支持并行
    发表于 03-22 15:04

    何解决stm32 485串口数据的收发问题?

    何解决stm32 485串口数据的收发问题?
    发表于 12-13 06:50

    Go语言及Beego框架环境搭建相关资料推荐

    就完成了。  天生支持并发,可以充分的利用多核,很容易实现并发。  25个关键字,但是表达能力很强大,几乎支持大多数你在其他语言见过的特性:继承、重载、对象等。  内置强大的工具,Go
    发表于 10-17 16:57

    网易有道CEO周枫推荐Go语言并介绍Go语言的3个优点

    网易有道CEO周枫推荐Go语言。他认为Go很好地继承了C语言灵活、简单有效的思想;Go有很高的生产效率;
    的头像 发表于 01-31 14:11 5154次阅读

    详析Java线程进程的并发问

    并发问题发生的前提条件一定是资源共享,这里的资源一般指的是数据,共享指的是多线程之间共享。
    的头像 发表于 07-07 11:44 2349次阅读

    详解GO语言的趋势与使用情况

    Go 语言简单易学、性能优良。JetBrains Blog 发布了Go 语言的调查报告,看看GO 语言
    的头像 发表于 03-17 11:05 3006次阅读

    Go语言凭借什么成为云原生第一语言的?

    偶然看到有人说, Go 语言目前的火爆可能就是昙花一现而已。这个观点我当然是不认同的。 近几年,关于 Go 与 Java 还有 C 的对比和讨论愈演愈烈,但不可否认的是,在十年多的时间里,Go
    的头像 发表于 04-22 10:15 3135次阅读
    <b class='flag-5'>Go</b><b class='flag-5'>语言</b>凭借什么成为云原生第一<b class='flag-5'>语言</b>的?

    golang并发机制和其他语言在实现上有什么不同

    golang 并发机制和其他语言在实现上有什么不同?为什么能做到高效快速?本文做了详细介绍。 由于对普通语法的介绍网上资源极多,Go 官方的上手指南 A Tour of Go: htt
    的头像 发表于 07-29 16:35 1419次阅读
    golang<b class='flag-5'>并发</b>机制和其他<b class='flag-5'>语言</b>在实现上有什么不同

    go语言枚举类型怎么用

    go 语言枚举类型是这么用的?在什么场景下会用到枚举?本文对 go 语言枚举做了详细讲解。 枚举,是一种重要的数据类型,由一组键值对组成,通常用来在编程
    的头像 发表于 09-02 09:43 5129次阅读

    带你了解go语言中的闭包

      【 导读】什么是闭包? 什么场景下会用闭包 ? 本文对 go 语言中的闭包做了详细介绍。 闭包是由函数及其相关引用环境组合而成的实体(即:闭包=函数+引用环境)。 Go中的闭包 闭包是函数式
    的头像 发表于 11-02 15:27 2389次阅读

    Go并发模型的实现原理

    Go语言是为并发而生的语言Go语言是为数不多的在语言
    的头像 发表于 04-15 08:49 1340次阅读

    go语言中怎么使用HTTP代理

    go语言中怎么使用HTTP代理。
    的头像 发表于 09-01 14:41 2372次阅读