MATLAB 中的矢量化是如何工作的?

How does vectorization in MATLAB work?

我想知道 MATLAB 如何处理向量化运算?

Data1 = fread(fin1, 10e6, 'uint8');
Data2 = fread(fin2, 10e6, 'uint8');
DiffA = diff(Data1);
DiffB = diff(Data2);

MATLAB 是否使用一种 SIMD 并行来执行此代码?它使用矢量处理器(如 GPU)还是仅使用系统内核(在多核系统中)?

MATLAB 使用 JIT 来加速计算。我没有找到关于 JIT 的明确信息,只有一般性建议。在我自己的用例中,我更喜欢将其视为 Java JIT,因为优化技术非常匹配。 MATLAB 在提高性能方面做了 4 个主要步骤:

  • 在 R13 (2002) 中引入了 JIT
  • 在R2006b中引入了无临时存储的就地计算,详见文档page 7
  • 在 R2007 中引入了多线程(在引擎中,而不是在并行工具箱中),在 R2008 中被广泛采用
  • 在 R2016 中引入了广泛采用 JIT 的新引擎

有关更多详细信息,请参阅 this 博客 post,评论非常有用。我知道的主要事情是在较新的版本中 "clean all" 删除了会话代码中的预编译。 亚尔奥特曼tinkered JIT and wrote a perfect book on MATLAB performance. Some details on guts and usage of MATLAB JIT are available here. For introduction on performance I'd recommend to start with official manual

OK,首先考虑C而不是MATLAB,因为i) C更接近机器和ii) MATLAB是用C编写的(至少,大多数语言执行引擎,几乎所有数字代码是用 C 编写的 - 目前桌面主要是基于 Java,但这与此处无关)。

所以如果你在 C 中有一个循环,比如

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

这是让计算机将AB的元素一一添加到数组C中。然而,一些处理器(向量处理器,最现代的 CPUs 是)可能能够使用 SIMD(单指令,多数据)一次执行其中的几个加法) 操作说明。所以你可以重写循环说

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

在这种情况下,将同时进行四次加法。这是一个矢量化 C 代码的简单示例,通过部分展开循环。

请务必注意,您不必在 C 代码中显式执行此操作,因为您的 C 编译器非常聪明。它会注意到您的代码中可以矢量化的部分,并会在编译之前为您重写这些部分。编译器在这方面非常擅长,但它无法掌握所有内容,如果您了解矢量化在 CPU 中的工作原理,那么您可以通过以特定方式构建代码来为编译器提供提示,并且您可以明确告诉编译器做特定的事情。

另请注意,这种矢量化虽然是一种简单的并行形式,但甚至可以在单核上使用 CPU(只要它是矢量处理器,最现代的 CPU是)。并行性发生在 CPU 的寄存器级别,通过使用同一指令一次对多个数据位进行操作。在多核 CPU 或 GPU 中,跨内核还有其他形式的并行性。

现在回到 MATLAB - MATLAB 实现了多种形式的并行性,包括多线程、跨内核和集群的显式并行性以及 GPU 并行性(其中一些需要附加产品,例如 Parallel Computing Toolbox)。但在其核心,MATLAB 实现了一组高度优化、高度矢量化的 C 例程,用于数值处理和线性代数。

与 C 不同,MATLAB 不是一种编译型语言 - 它是通过 JIT 编译器进行解释的。但它仍在查看您的代码并尝试找到可用于快速执行代码的优化。如果您以特定方式编写代码,则可以帮助 MATLAB 选择最佳执行方式。

例如代码

a = rand(3,4);
b = rand(4,2);


c = zeros(size(a,1),size(b,2));
for i = 1:size(a,1)
    for j = 1:size(b,2)
        element = 0;
        for k = 1:size(a,2)
            element = element + a(i,k).*b(k,j);
        end
        c(i,j) = element;
    end
end

一样
a = rand(3,4);
b = rand(4,2);

d = a*b;

但在后一种情况下,MATLAB 知道它可以调用其超级优化的库之一进行矩阵乘法,而不是将元素一个一个地相乘和累加。这是矢量化 MATLAB 代码的一个简单示例。