背景
笔者在工程中经常使用golang来进行开发,用go来写高并发程序也确实是爽的不要不要的。前段时间在读了William Kennedy的文章Scheduling In Go : Part III - Concurrency后对如何使用并行更高效的优化golang代码有了进一步的理解,在此记录一下。
原文地址:https://www.ardanlabs.com/blog/2018/12/scheduling-in-go-part3.html
一:并发与并行
这是一个老生常谈的问题了,随便搜索一下都能得到大量地回答,并发与并行的概念如下。
并发(concurency):并发表示多个任务可以在同一时间段运行,但不代表能在同一时刻运行,比如在单核处理器上运行多个任务。
并行(parallelism):并行代表任务可以同时运行,比如在多核处理器上运行多个任务(每个核在同一时间都在处理任务)。
在实际工作中,我们在遇到一个问题的时候,往往会先想到一个串行的解决问题的方案;然后才会进一步思考如何更快的解决问题,也就是利用并行解决问题,这里说并行不是并发是因为并发并不能加快解决问题的速度,只有并行才可以。
那么什么样的问题才能通过并行加速解决呢,我们一起来思考下面几个问题。
二:计算数组总和
问题:计算一个整形数组之和是多少?
根据问题我们很快能够写出代码如下:
func add(num []int) int64 {
var sum int64 = 0
for _, i := range num {
sum += int64(i)
}
return sum
}
分析一下这个问题可不可以使用并行的方式来处理,答案当然是可以的,具体原因后面再说,读者可以自己先思考一下。使用并行的方式处理,需要用到多个goroutine一起来进行计算,把num数组拆为num1,num2,num3……numn等,然后每个goroutine计算自己的那份,最后加到一起,代码实现如下:
func addConcurrent(gNumber int, num []int) int64 {
lenght := len(num) / gNumber
wg := sync.WaitGroup{
}
wg.Add(gNumber)
var answer int64 = 0
for i := 0; i < gNumber; i++ {
go func(index int) {
defer wg.Done()
start := index * lenght
end := (index + 1) * lenght
if index == gNumber - 1 {
end = len(num)
}
var sum int64 = 0
for i