并行计算的两种方式:
- 步骤并行:将一个计算公式拆解为多个计算步骤,为每一个步骤作为一个独立的协程计算
- 数据并行:将原始数据拆分成多个的较小的数据单元,为每一个数据单元作为一个独立的协程计算,最后再合并数据
数据并行: 可以解决原始数据庞大的计算,将数据拆分成单个较小的数据集,利用CPU多个核心,同时计算,最后对数据进行合并。最大效率的利用CPU的多核心特征
步骤并行: 可以解决拆解复杂的计算,减少上一个计算等待上一个计算的输出的时间或者减少由于IO带来的CPU空闲时间,高效率的利用CPU。
我认为在日常的学习和工作中,根据任务情况、业务场景,单独使用(使用其中一种),或者组合使用(同时使用),这两种并行的方法,,可以提高程序对硬件资源的利用率。
案例1(数据庞大,计算简单):
从数据库表中取出两个字段的数据A
,B
进行计算,即\(\sum_i^{n} A_i*B_i\),其实有10亿条数据。如果单纯的一次从数据库中读出来,然后再进行计算,这是一种非常消耗时间和内存的操作。那么我们改怎么解决这个问题呢?
分析一些我们的业务需求。我们是读取大量数据,然后\(\sum_i^{n} A_i*B_i\)比较简单的计算。首先,一次性读取10亿条数据,肯定是不可取的,我们得通过异步的方式读取
A
和B
的数据,然后因为是大量数据,所以我们数据并行的方式计算。
伪代码:
var sum float32
for{
tData<-data//data是一个chan,从data中异步读取数据
go func(){
for _,value:=tData{
sum+= value.a*value.b
}
}()
}
案例2(数据庞大,计算复杂):
从数据库表中取出两个字段的数据A
,B
进行计算,即\(\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亿条数据,肯定是不可取的,我们得通过异步的方式读取
A
和B
的数据,然后因为是大量数据,所以我们数据并行的方式计算。
伪代码:
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
}