【问题标题】:Preallocation and Vectorization Speedup预分配和向量化加速
【发布时间】:2014-02-05 06:30:44
【问题描述】:

我正在尝试提高我尝试运行的脚本的速度。

代码如下:(我的机器=4核win 7)

clear y;
n=100;
x=linspace(0,1,n);
% no y pre-allocation using zeros
start_time=tic;

for k=1:n,
    y(k) =  (1-(3/5)*x(k)+(3/20)*x(k)^2 -(x(k)^3/60)) / (1+(2/5)*x(k)-(1/20)*x(k)^2);
end

elapsed_time1 = toc(start_time);
fprintf('Computational time for serialized solution: %f\n',elapsed_time1);

上面的代码给出了 0.013654 的经过时间。

另一方面,我尝试通过在上面的代码中添加y = zeros(1,n); 来使用预分配,但运行时间在~0.01 左右相似。任何想法为什么?有人告诉我它会提高 2 倍。我错过了什么吗?

最后,Matlab 中是否有任何类型的向量化可以让我忘记上面代码中的 for 循环?

谢谢,

【问题讨论】:

  • 试试 n=1000000;你应该看到区别。 100 太小了。

标签: matlab


【解决方案1】:

在您的代码中:尝试使用n=10000,您会发现更多差异(在我的机器上几乎是 10 倍)。

当变量的大小很大时,这些与分配相关的事情最为明显。在这种情况下,Matlab 更难为该变量动态分配内存。


为了减少操作的数量:将其向量化,并重用中间结果以避免幂:

y = (1 + x.*(-3/5 + x.*(3/20 - x/60))) ./ (1 + x.*(2/5 - x/20));

基准测试

n=100:

Parag's / venergiac's 解决方案:

>> tic
for count = 1:100
y=(1-(3/5)*x+(3/20)*x.^2 -(x.^3/60))./(1+(2/5)*x-(1/20)*x.^2);
end
toc
Elapsed time is 0.010769 seconds.

我的解决方案:

>> tic
for count = 1:100
y = (1 + x.*(-3/5 + x.*(3/20 - x/60))) ./ (1 + x.*(2/5 - x/20));
end
toc
Elapsed time is 0.006186 seconds.

【讨论】:

  • 真的吗?在 n=1000000 时,我没有看到超过 2 倍的速度提升事件。
  • @Parag 谢谢!我重用了here的技巧,其实
  • @LuisMendo MATLAB 是一个解释器,但你觉得有什么语言(或软件)可以自动识别它,在编译时进行优化,这样用户就不必知道这些技巧?
  • @Parag 我真的不知道...对于编译器来说应该不会太难。无论如何,程序员也不难(而且很有趣!),以这些术语来思考以减少操作:-)
  • @LuisMendo 这并不难,它不会很快发生。你不会意识到,你有 14K 的声望......开玩笑......
【解决方案2】:

您不需要for 循环。将 for 循环替换为以下内容,MATLAB 将处理它。

y=(1-(3/5)*x+(3/20)*x.^2 -(x.^3/60))./(1+(2/5)*x-(1/20)*x.^2);

当向量变得更大时,这可能会带来计算优势。较小的尺寸是您看不到预分配效果的原因。阅读this 页面,了解有关如何提高性能的更多提示。

编辑:我观察到在更大的尺寸 n>=10^6 上,当我尝试以下操作时,我的性能得到了持续的提升:

x=0:1/n:1;

而不是使用linspace。在n=10^7,通过不使用linspace,我获得了 0.05 秒(0.03 对 0.08)。

【讨论】:

  • 可以通过重用中间结果来减少操作次数(和经过的时间)以避免权力;看我的回答。
  • @LuisMendo 我用你和我的代码对 n=100000 进行了测试,我得到了 10 倍的改进(1.132 vs 0.155)。手动分解能产生如此大的不同,这让我感到非常惊讶。
【解决方案3】:

尝试每个元素的操作元素(.*.^

clear y;
n=50000;
x=linspace(0,1,n);
% no y pre-allocation using zeros
start_time=tic;

for k=1:n,
    y(k) =  (1-(3/5)*x(k)+(3/20)*x(k)^2 -(x(k)^3/60)) / (1+(2/5)*x(k)-(1/20)*x(k)^2);
end

elapsed_time1 = toc(start_time);
fprintf('Computational time for serialized solution: %f\n',elapsed_time1);

start_time=tic;
y =  (1-(3/5)*x+(3/20)*x.^2 -(x.^3/60)) / (1+(2/5)*x-(1/20)*x.^2);

elapsed_time1 = toc(start_time);
fprintf('Computational time for product solution: %f\n',elapsed_time1);

我的数据

序列化解决方案的计算时间:2.578290

序列化解决方案的计算时间:0.010060

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-08-31
    • 1970-01-01
    • 1970-01-01
    • 2020-12-17
    • 2023-03-28
    • 2021-08-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多