is 'arrayfun' faster much more than 'for' loop?

121 views (last 30 days)
vx2008
vx2008 on 9 Feb 2017
Commented: Bruno Luong on 15 Jan 2021
now I have written a function which use a 'for' loop and it runs slowly because of large calculations; If i use 'arrayfun' to replace 'for' loop, the function would run faster much?
  1 Comment
Adam
Adam on 9 Feb 2017
Edited: Adam on 9 Feb 2017
Simplest way to understand is to implement both options and time them using
doc timeit
I do this regularly when I want to understand which of multiple methods of implementing something is faster. As Walter says below though, if you just want a quick answer arrayfun is usually slower.

Sign in to comment.

Answers (3)

Walter Roberson
Walter Roberson on 9 Feb 2017
Typically arrayfun() runs more slowly, because it needs to invoke a function call each time through its internal for loop. There is still a for loop; it is just hidden.
  1 Comment
Walter Roberson
Walter Roberson on 12 Feb 2017
Here is some code to test out various possibilities.
The items are:
  1. plain for loop
  2. arrayfun
  3. if false arrayfun else for loop
  4. arrayfun_is_faster = false; if arrayfun_is_faster arrayfun else for loop
  5. retest plain for loop
The code has two outputs: first the ratio of times relative to the plain for loop, and secondly the mean time of each of the groups.
The times will be plotted along with a mark indicating the mean time. The y limits are set the same on all of the plots so you can directly compare the height of the mean lines.
If you have the statistics toolbox a boxplot will be presented as well.
In my test, arrayfun is consistently the slowest, by 30% to 60%.
However, in my tests, the initial test of plain for loop was often the second slowest, even though the for loop logic is copied exactly the same to #3 and #4, measurably slower than re-running the exact same for loop after the other tests were done. Testing for a variable set false was about 1% slower than "if false": slower but not much slower.
Why was the initial running of the plain for loop slower than re-running it later? I notice that even though I re-run the timeit 200 times, the variability of timings on the first probe of plain for loops is much higher than later. I have no explanation for that.
I could hypothesize that the JIT has does not fully optimize until the code has been run a few hundred times (each timeit() call is going to call the actual routine a number of times.)

Sign in to comment.


Jan
Jan on 9 Feb 2017
Edited: Jan on 9 Feb 2017
While in all of my tests arrayfun was slower, I have collected these tests in an M-file and run it with every new Matlab release. I'm used to write the for-loop approach at first, add the arrayfun afterwards and compare the results and speed by unit-testing. Then I comment out the slower method.
This demands for an exhaustive commenting, because it is too confusing, if somebody finds commented code some years later and has no idea, why it is not used. Or imagine that the arrayfun approach is modified later, but the commented for approach is not. This will confuse a reader massively, if it is not explained clearly.
Care for optimizing the bottlenecks only. So called premature optimization can increase the debug time dramatically, such that the total program time (programming + debugging + documenting + running) might increase.
Summary: Try it.
  3 Comments
Jan
Jan on 11 Feb 2017
Edited: Jan on 11 Feb 2017
While the time penalty will be tiny, the 2nd version will save minutes or more by avoiding speculations during debugging.
Walter Roberson
Walter Roberson on 12 Feb 2017
Looks like less than 1% penalty for "if arrayfun_is_faster"

Sign in to comment.


Arjan Lampe
Arjan Lampe on 6 May 2020
It seems arrayfun is much, much more slower. Or am I messing something up?
A simple (too simple?) test. Make some test function:
testf.m:
function m = testf(m)
%TESTF Summary of this function goes here
% Detailed explanation goes here
for c_m = 1:numel(m)
m(c_m) = sqrt(m(c_m));
end
end
And then:
>> m = rand(15)
>> tic; for ii = 1:1000000; testf(m); end; toc
Elapsed time is 1.405036 seconds.
>> tic; for ii = 1:1000000; arrayfun(@sqrt,m); end; toc
Elapsed time is 116.857802 seconds.
That is a factor 83 slower...
  2 Comments
Evan Voyles
Evan Voyles on 15 Jan 2021
I think the factor for which it is slower largely depends on what function you are applying to the array. For example, I tested arrayfun vs a forloop, squaring the elements, and the speed difference was a factor of two. While this is concrete evidence that we should always use for loops instead of arrayfun, it's obvious that the benefit varies.
It's kind of sad because writing a single command arrayfun is so much more appealing that writing out the full for loop. I guess that's the sacrifice that we make for performance ;)
Bruno Luong
Bruno Luong on 15 Jan 2021
twice only? Put it in a function to have JIT correctly speed up the loop
function forloopvsarrayfun
x = rand(1,1e6);
tic
y = zeros(size(x));
for i=1:length(x)
y(i) = x(i).^2;
end
t1=toc;
tic
y = arrayfun(@(x) x.^2, x);
t2=toc;
fprintf('for loop time = %g\n', t1);
fprintf('arrayfun time = %g\n', t2);
fprintf('arrayfun time is %g time slower\n', t2/t1);
end
This is the result with R2020B
for loop time = 0.0042138
arrayfun time = 1.99038
arrayfun time is 472.348 time slower

Sign in to comment.

Categories

Find more on Loops and Conditional Statements in Help Center and File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!