go

go并行计算大量数据的方法

Posted by Chen Quan on August 17, 2019

并行计算的两种方式:

  • 步骤并行:将一个计算公式拆解为多个计算步骤,为每一个步骤作为一个独立的协程计算
  • 数据并行:将原始数据拆分成多个的较小的数据单元,为每一个数据单元作为一个独立的协程计算,最后再合并数据

数据并行: 可以解决原始数据庞大的计算,将数据拆分成单个较小的数据集,利用CPU多个核心,同时计算,最后对数据进行合并。最大效率的利用CPU的多核心特征

步骤并行: 可以解决拆解复杂的计算,减少上一个计算等待上一个计算的输出的时间或者减少由于IO带来的CPU空闲时间,高效率的利用CPU。

我认为在日常的学习和工作中,根据任务情况、业务场景,单独使用(使用其中一种),或者组合使用(同时使用),这两种并行的方法,,可以提高程序对硬件资源的利用率。

案例1(数据庞大,计算简单):

从数据库表中取出两个字段的数据AB进行计算,即\(\sum_i^{n} A_i*B_i\),其实有10亿条数据。如果单纯的一次从数据库中读出来,然后再进行计算,这是一种非常消耗时间和内存的操作。那么我们改怎么解决这个问题呢?

分析一些我们的业务需求。我们是读取大量数据,然后\(\sum_i^{n} A_i*B_i\)比较简单的计算。首先,一次性读取10亿条数据,肯定是不可取的,我们得通过异步的方式读取AB的数据,然后因为是大量数据,所以我们数据并行的方式计算。

伪代码:

var sum float32

for{

    tData<-data//data是一个chan,从data中异步读取数据
   
    go func(){
    
        for _,value:=tData{
        
            sum+= value.a*value.b
            
        }
        
    }()
    
}


案例2(数据庞大,计算复杂):

从数据库表中取出两个字段的数据AB进行计算,即\(\sum_i^{n} A_i*B_i+\sum_i^n A_i^{B_i}+B_i^{A_i}\),其实有10亿条数据。如果单纯的一次从数据库中读出来,然后再进行计算,这是一种非常消耗时间和内存的操作。那么我们改怎么解决这个问题呢?

分析一些我们的业务需求。我们是读取大量数据,然后\(\sum_i^{n} A_i*B_i\)比较简单的计算。首先,一次性读取10亿条数据,肯定是不可取的,我们得通过异步的方式读取AB的数据,然后因为是大量数据,所以我们数据并行的方式计算。

伪代码:

var sum float32
step1Out := make(chan float32,100)
step2Out := make(chan float32,100)
out := make(chan float32,100)
for{
    //data是一个chan,从data中异步读取数据
    
    go step1(data,step1Out)//step1 = \sum_i^{n} A_i*B_i
    go step1(data,step2Out)//step2 = \sum_i^n A_i^{B_i}+B_i^{A_i}
    go finalStep(step1Out,step2Out,out)//sum = step1+step2
}