并发模型
总的来说,有三种并发模型:
- Multi-core:利用多核处理器进行基于进程或线程的并发,不同的核心可以处理不同的指令流。
- SIMD:利用一个核心内的多个ALU单元,并发处理一个同一指令且相互独立的数据。这是一种充分利用硬件的并发形式,对于特定情况下的数据处理拥有很高的利用率。
- Superscalar:一个核心充分利用一个指令流内的ILP指令,从而并发的处理一个指令流。
处理器模型
最简单的处理器核心的模型可以看成三个部分
- 取指与解码器:从指令流获取指令
- ALU:执行指令
- 执行上下文:进程的执行环境
SIMD:single-instruction,multi-data
如一个拥有八个处理单元的核心。若数据之间是独立的,那么一个指令可以取得多个数据,然后同时处理这些数据。
如Intrinsics函数,可以用于操作SIMD指令集。
以三角函数的泰勒展开函数为例,该函数以多个因变量为输入值,输出多个结果。
// sin(x) = x - x^3/3! + x^5/5! ...
void sinx(int N,int terms,float* x,float *result){
for(int i = 0;i < N;i++){
float value = x[i];
float numer = x[i] * x[i] * x[i];
int denom = 6; // 3!
int sign = -1;
for(int j = 1;j <= terms;j++){
value += sign * numer / denom;
numer *= x[i] * x[i];
denom *= (2*j + 2) * (2*j + 3);
sign *= -1;
}
result[i] = value;
}
}
SIMD指令改进的版本如下。__m256可以以256位为指令的操作单位,在下函数中则体现为同时载入八个float元素进行运算。
SIMD的思想是对于互不相关的数据集,可以共享同一条指令。
然而,若代码中出现了分支,处理器又如何应对呢?
float x = x[i];
if(x > 0){
// do something..
}else{
// do something..
}
result[i] = x;
多核之间可以处理不同的指令流,但是单核只能处理一条指令流。
处理器的处理方式是经过分支预测后,对于预测为真的数据集执行一种指令,否则执行另一种指令。在时间轴上,这两种是顺序执行的。
然而在分支走向不均匀,最坏情况是只有一个预测为真或只有一个预测不为真时,只有一个运算单元正在工作,其他单元都处于闲置状态。
对于SIMD来说,这种情况是应该避免出现的。
Instruction stream coherence表示指令集中,同一个指令对所有的数据集都并发地进行处理。
多核处理器
对于多核处理器来说,其拥有多个如上所述的核心,可以在不同的指令流中进行SIMD运算。