golang for循环 外部停止_Golang 并发初入

本文探讨了在Golang中使用并发的原因和方法。作者通过分析接口耗时,发现循环请求外部资源是主要耗时点,从而引入并发设计。并发在不相关代码模块间效果显著,但并发启动时间需考虑,过多并发可能导致效率降低。通过实例展示了并发求和与无并发的性能对比,并强调并发设计需谨慎,控制并发数能有效提升程序效率。
摘要由CSDN通过智能技术生成

为什么要用并发?

这个疑问产生在如下情境:某次,调用某个接口时,我发现千辛万苦写完的接口,它返回的特别慢,居然要 7/8 s!

整个人都不好了,窘迫,不解。

于是尝试将代码重构,删掉多余的逻辑,发现几乎没有什么变化。于是通过中断代码调试来测验程序运行耗时的分布状况,发现时间都耗在了循环请求外部资源这个模块,反而复杂的逻辑处理并没有占据多少资源。于是,想起学习golang时用的教科书:

前言 · Go语言圣经​books.studygolang.com
bd645f77417d65be280293419c13f360.png

其中,第八章讲到了Goroutines,也就是并发设计。这意味着我可以在某些可以为某些代码模块添加并发设计,减少程序耗时。


如何使用并发设计?

根据这段时间的摸索,我发现在项目中goroutines的应用场景大多是两个及以上不相关的代码模块之间。如:

var tmp []int = [1,...,10000000]
for _, v := range tmp {
    go func(v int) {
        //todo
     }(v)
}

上述代码是golang并发设计的粗略展示,在大多数情况下,goroutine内的todo要相对复杂,因为goroutines即使很快启动,也是需要一定时间,倘若一次并发启动的时间大于goroutines实际起作用的时间,那么这个并发设计不仅不能做到提高程序速率,相反还会降低。

为了证实我的结论,我通过一个简单的例子来阐述:

  • 容量为1000000的数组,无并发求和,求程序运行时间;
func Test(){
_stamp := time.Now().UnixNano()
    tmp := []int{}
    for i := 0; i < 10000000; i++ {
	tmp = append(tmp, i)
    }
    sum := 0

     for _, v := range tmp {
	sum += v
     }
     stamp_ := time.Now().UnixNano()

     c.JSON(http.StatusOK, gin.H{
	"status": "success",
	"result": sum,
	"ms":     (stamp_ - _stamp) / 1000000,
     })
}

结果如下,耗时5ms。

{
    "ms": 5,
    "result": 49999995000000,
    "status": "success"
}
  • 容量为1000000的数组,并发求和,求程序运行时间;
func AgentsPing(c *gin.Context) {
	sum := 0

	tmp := []int{}
	for i := 0; i < 10000000; i++ {
		tmp = append(tmp, i)
	}
	finish := make(chan int)
	var wg sync.WaitGroup
	wg.Add(10000000)

	_stamp := time.Now().UnixNano()
	for _, v := range tmp {
		go func(v int) {
			sum += v
		}(v)

		defer wg.Done()
	}
	go func() {
		wg.Wait()
		finish <- 1
	}()

	stamp_ := time.Now().UnixNano()

	c.JSON(http.StatusOK, gin.H{
		"status": "success",
		"result": sum,
		"ms":     (stamp_ - _stamp) / 1000000,
	})
}

结果如下:耗时5947ms。

{
    "ms": 5947,
    "result": 49999995000000,
    "status": "success"
}

小结

综上所述,并发设计需慎重,并不是所有场合都适合并发,因为启动并发与并发作用时间并不明确。在项目中,要控制并发数,前几日我花费了数个小时时间将同事的并发代码梳理了一遍,发现他在所有循环中都用上了并发,去掉不合理的并发后,该接口的效率约莫提了3-4倍,前端调取的等待时间大大减少。

这是一个艰难的历程,并发是双刃剑...

并发另一个值得提的就是和channel的结合使用,同样重要,下次有空再讲~


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值