一个通过并发计算优化Go程序的记录 | 青训营

149 阅读5分钟

1.目标任务:

在编写程序的时候,我们有的时候需要进行一些耗时较长的计算任务,比如在以下这段代码当中,我们就计算了到100000000的累加和

package main

import (
	"fmt"
	"time"
)

func main() {
	start := time.Now()

	// 模拟一个耗时的计算任务
	result := calculate(100000000)

	elapsed := time.Since(start)
	fmt.Printf("计算结果:%d\n", result)
	fmt.Printf("耗时:%s\n", elapsed)
}

func calculate(n int) int {
	result := 0
	for i := 0; i <= n; i++ {
		result += i
	}
	return result
}

有没有什么办法使得计算速度更快

2.问题所在:

不难看出,在这段代码中,我们遍历对0到100000000的所有数字,从而求取其累加和,假设我们这里用N来取代100000000,就可以得出一个更加泛化的计算模型,这个代码的时间复杂度为O(N),即算法的时间复杂度随着数据量的增大几倍,耗时也增大几倍。

这种遍历的方式虽然可以完成任务,但是其性能上有较大的问题,故此我们需要引入一些方案来对这段代码进行优化

3.优化思路 并发计算:

并发计算(英语:Concurrent computing,或译为并发处理、共时计算),是一种程序计算的形式,在系统中,至少有两个以上的计算在同时运作,计算结果可能同时发生。用来实现并发系统。用更加通俗的话来说,并发计算就是在执行程序的时候,不再通过线性的方式对需要进行计算的任务进行排列,而是将需要进行计算的任务通过特定的方式分配给不同计算实体,从而加快并发计算的计算方式

在并发计算的具体实现方面上并发计算的实现方式包括多线程编程、并行计算、分布式计算等。多线程编程是指在单个程序中创建多个线程,每个线程执行不同的任务,通过线程间的协作和资源共享来实现并发。并行计算是指将一个计算任务分成多个子任务,并在多个处理器或计算节点上同时执行,最后将结果合并得到最终结果。分布式计算则是指将一个计算任务分发到多台计算机或计算节点上进行处理,通过网络通信进行协作和数据交换。

并发计算的应用场景可以说是多种多样的,比如:科学计算、工程模拟、天气预报等大规模计算密集型任务中,往往可以采用并发计算来对计算任务进行优化。并发计算的另外一大应用场景是在网络编程中,通过并发处理客户端请求可以提高系统的吞吐量和响应速度。而在分布式系统或云计算环境中,并发计算可用于处理并发请求、分布式任务调度和数据同步。

在针对这段代码的优化过程中,我们主要采用多线程编程的方式来对其进行优化,具体的优化思路是将这一组数分为各个区间,在不同的区间内先并发地进行求和计算,最终再将所有区间加起来,得到最终的结果,这样做的原因有以下两点:

  1. Go对于多线程编程有较好的支持,可以通过函数来调用多核心处理器
  2. 在Go当中实现多线程编程有较好的灵活性,可以根据自己的需求对多线程编程进行精细化操作。
  3. 累加求和的算法流程适合进行分区间计算。

4.并发计算优化步骤:

我们可以通过并发计算的方式来让程序变得更加高效,来让这段代码变得更加高效。

package main

import (
	"fmt"
	"runtime"
	"sync"
	"time"
)

func main() {
	start := time.Now()

	// 设置使用多核心处理器
	runtime.GOMAXPROCS(runtime.NumCPU())

	// 使用并发计算
	result := concurrentCalculate(100000000)

	elapsed := time.Since(start)
	fmt.Printf("计算结果:%d\n", result)
	fmt.Printf("耗时:%s\n", elapsed)
}

func concurrentCalculate(n int) int {
	result := 0
	numCPU := runtime.NumCPU()
	wg := sync.WaitGroup{}
	wg.Add(numCPU)

	// 将计算任务分配给多个goroutine并行执行
	for i := 0; i < numCPU; i++ {
		go func(start, end int) {
			defer wg.Done()
			partialSum := 0
			for i := start; i <= end; i++ {
				partialSum += i
			}
			result += partialSum
		}(i*n/numCPU+1, (i+1)*n/numCPU)
	}

	// 等待所有goroutine完成
	wg.Wait()

	return result
}

在这段程序中,我们主要通过以下4个步骤来实现了基于多线程编程的并发计算

  1. 使用runtime.GOMAXPROCS函数将程序设置为使用多核心处理器,以充分利用计算资源。
  2. 使用并发编程的方式,将计算任务分配给多个goroutine并行执行,提高计算速度。
  3. 使用sync.WaitGroup来等待所有goroutine完成计算任务,以确保结果的正确性。
  4. 将计算任务分割成多个部分,每个部分由一个goroutine负责计算,最后将各部分的结果累加得到最终结果。

5. 总结

在本文中,我们主要针对一个较为简单的计算任务进行了优化,在优化过程中主要采用了多线程编程的方式实现了并发计算 最终针对程序进行了优化。而在实际的计算任务进行优化的时候,并非只有并发计算这一种方式,在实际的编程过程中,需要根据实际情况来选取真正适用的优化方案。