什么是“矢量化”?

What is “vectorization”?

好几次,我在matlab中遇到过这个词,fortran…其他一些…但我从来没有找到一个解释它是什么意思,它是什么作用?所以我在这里问,什么是矢量化,它意味着什么,例如,"一个循环是矢量化的"?


许多CPU都有"vector"或"simd"指令集,这些指令集将同一操作同时应用于两个、四个或更多数据块。现代x86芯片有SSE指令,许多PPC芯片有"Altivec"指令,甚至一些ARM芯片也有一个称为Neon的矢量指令集。

"矢量化"(简化)是重写一个循环的过程,这样它就不会处理一个数组的单个元素n次,而是同时处理(比如)数组的4个元素n/4次。

(我选择4是因为它是现代硬件最可能直接支持的;术语"矢量化"也用于描述更高级别的软件转换,在这种转换中,您可以完全抽象出循环,只描述对数组的操作,而不是组成它们的元素)

矢量化和循环展开之间的区别:考虑下面这个非常简单的循环,它添加两个数组的元素并将结果存储到第三个数组中。

1
2
for (int i=0; i<16; ++i)
    C[i] = A[i] + B[i];

展开此循环会将其转换为如下类型:

1
2
3
4
5
6
for (int i=0; i<16; i+=4) {
    C[i]   = A[i]   + B[i];
    C[i+1] = A[i+1] + B[i+1];
    C[i+2] = A[i+2] + B[i+2];
    C[i+3] = A[i+3] + B[i+3];
}

另一方面,矢量化会产生如下结果:

1
2
for (int i=0; i<16; i+=4)
    addFourThingsAtOnceAndStoreResult(&C[i], &A[i], &B[i]);

其中"add4thingsatonceandstoreresult"是编译器用于指定向量指令的任何内部函数的占位符。注意,一些编译器能够自动向量化像这样的简单循环,这通常可以通过编译选项启用。更复杂的算法仍然需要程序员的帮助来生成好的向量代码。


矢量化是将标量程序转换为矢量程序的术语。矢量化程序可以从一条指令中运行多个操作,而标量只能一次对操作数进行操作。

维基百科:

标量方法:

1
2
3
4
for (i = 0; i < 1024; i++)
{
   C[i] = A[i]*B[i];
}

矢量化方法:

1
2
3
4
for (i = 0; i < 1024; i+=4)
{
   C[i:i+3] = A[i:i+3]*B[i:i+3];
}


它指的是在一个单步中对数字列表或"向量"进行单一数学运算的能力。你经常在Fortran中看到它,因为它与科学计算有关,而科学计算与超级计算有关,在超级计算中矢量化算法首次出现。如今,几乎所有的台式CPU都通过英特尔的SSE等技术提供某种形式的矢量化算法。GPU还提供一种矢量化算法。


矢量化在科学计算中被大量使用,在科学计算中需要有效地处理大量数据。

在实际的编程应用程序中,我知道它在numpy中使用(不确定其他的用法)。

numpy(在python中用于科学计算的包)使用矢量化来快速操作n维数组,如果使用内置的python选项来处理数组,通常会慢一些。

尽管有大量的解释,下面是numpy文档页面中的矢量化定义。

矢量化描述了代码中没有任何显式循环、索引等——当然,这些事情发生在优化的、预编译的C代码中,只是"幕后"。矢量化代码有很多优点,其中包括:

  • 矢量化代码更简洁,更易于阅读

  • 更少的代码行通常意味着更少的错误

  • 代码更像标准的数学符号。(使正确的数学编码变得更容易构造)

  • 矢量化导致更多的"Python"代码。没有矢量化,我们的代码将到处都是低效的和难以读取循环。


  • 在简单的矢量均值算法寻优的话,所以它可以在processors utilize SIMD指令。 >

    AVX、avx2和指令集的avx512 perform(英特尔),同样的操作在一个在线指令多数据。你可以avx512均值为EG的在线操作。16(4字节整数值)规定的时间。那是什么,如果你有均值向量(16 integers双,和你想添加值,然后在每10 integers吧。你可以在线或者负荷值对通用寄存器(A,B,C)十六时代和perform一样操作或您可以使用相同的16×perform加值到全在线registers SIMD(XMM)和《青运perform,运行一次。这让computation速度上的矢量数据。 >

    在我们这对我们利用矢量化的优势,通过我们的日期,这样我们可以remodelling perform SIMD操作它和速度上的程序。 >

    唯一的问题是与矢量化处理条件。因为银行的执行分支流条件。这可以通过masking柄。由模拟的arithmetic操作条件为年。例如,如果我们想添加10至100 value if it is那么大。我们可以继承。 >

    1
    if(x[i] > 100) x[i] += 10; // this will branch execution flow.

    或者我们可以进入操作状态模型的状态向量C arithmetic奇迹信息了, >

    1
    2
    c[i] = x[i] > 100; // storing the condition on masking vector
    x[i] = x[i] + (c[i] & 10) // using mask

    虽然这是非常平凡的例子。我们thus,C是masking to perform向量,我们使用二元操作的基础上的,其值。这避免银行的执行分支流和enables矢量。 >

    我是我重要的矢量化,并行化。我们应该让thus,这是使用多个。有一天processors SIMD指令的所有现代大型compute workloads。我们可以到我们的代码使用OPTIMIZE SIMD指令的使用这些类似的矢量化,这是对我们的代码parrallelizing跑在现代多核心processors在线提供。 >

    我想让银行在OpenMP奖,这让你的代码使用矢量化的杂注。我认为他们是很好的起步点。同样可以说openacc论坛。 >

    请看上面的两个答案。我只是想补充一点,想要进行矢量化的原因是,超级计算机和多处理器可以很容易地在Paraell中执行这些操作,从而获得巨大的性能增益。在单处理器计算机上,不会有性能提升。