parfor loop with continue gives incorrect results
Show older comments
Consider the following code:
N = 1000;
failed = false( 1, N );
values = cell( 1, N );
n_failed = 0;
parfor idx = 1:N
try
if ( rand() > 0.7 )
n_failed = n_failed + 1;
error( '' );
end
catch err
failed(idx) = true;
continue;
end
values{idx} = rand( 1e3, 1 );
end
fprintf( 'N failed 1: %d\n\n', sum(failed) );
fprintf( 'N failed 2: %d\n', n_failed );
If I run this on my machine (macOS 10.12, r2017a), `sum(failed)` is 0, while `n_failed` is, as expected, ~300. What am I missing here? I don't see anything in the documentation about `continue` not being supported in a parfor loop?
4 Comments
Matt J
on 8 Oct 2018
while `n_failed` is, as expected, ~300
How can you have any expectations at all about sum(failed) or n_failed, when their values are driven by the randomization in
if ( rand() > 0.7 )
Walter Roberson
on 9 Oct 2018
Statistically approximately 300 would be most common.
Question: have you tried nnz() to cross check sum()?
Steve Chang
on 9 Oct 2018
Answers (1)
Don't pass an empty string '' to error() if you want the catch block to be triggered. An empty string apparently does not result in an error being thrown.
In other words, this works fine:
N = 1000;
failed = false( 1, N );
n_failed = 0;
parfor i = 1:N
try
if ( rand() > 0.7 )
n_failed = n_failed + 1;
error('an error');
end
catch
failed(i) = true;
continue
end
end
fprintf( 'N failed 1: %d\n\n', sum(failed) );
fprintf( 'N failed 2: %d\n', n_failed );
9 Comments
Steve Chang
on 9 Oct 2018
Matt J
on 9 Oct 2018
Bizarre. Well, I don't understand the problem, but I do find that removing the continue fixes it. I also find that moving the assignment to values up several lines also fixes it:
N = 1000;
failed = false( 1, N );
values = cell( 1, N );
n_failed = 0;
parfor idx = 1:N
values{idx} = rand( 1e3, 1 );
try
if ( rand() > 0.7 )
n_failed = n_failed + 1;
error( 'A' );
end
catch err
failed(idx) = true;
continue;
end
end
fprintf( 'N failed 1: %d\n\n', sum(failed) );
fprintf( 'N failed 2: %d\n', n_failed );
Steven Lord
on 9 Oct 2018
Don't pass an empty string '' to error() if you want the catch block to be triggered. An empty string apparently does not result in an error being thrown.
That is correct. The last item in the Tips section on the documentation page for the error function states that if all the inputs are empty, error does not throw an error.
Historically, error was often used with functions like nargchk that would return '' if the number of inputs was in the allowed range and an error message if not. Now, as the warning box at the top of the documentation page states, you should use narginchk (and/or nargoutchk) instead. Those will directly throw the error, so you don't need to wrap them in error calls.
The code above works, but I'm experiencing a different error with my original code.
That suggests that your original code is doing something different than the code you posted in Answers, and the differences between those two sections of code is relevant. Post your original code, or simplify the original code down to the minimal working example that reproduces the exact error you're seeing, and we may be able to offer guidance relevant to that original code.
That suggests that your original code is doing something different than the code you posted in Answers
@Steven Lord, The posted code does reproduce the problem, when a non-empty string is passed to error().
N = 1000;
failed = false( 1, N );
values = cell( 1, N );
n_failed = 0;
parfor idx = 1:N
try
if ( rand() > 0.7 )
n_failed = n_failed + 1;
error( 'A' );
end
catch err
failed(idx) = true;
continue;
end
values{idx} = rand( 1e3, 1 );
end
fprintf( 'N failed 1: %d\n\n', sum(failed) );
fprintf( 'N failed 2: %d\n', n_failed );
In R2018a, the above gives,
Error using test>(parfor consume)
Unable to perform assignment because the left and right sides have a different number
of elements.
Error in test (line 9)
parfor idx = 1:N
Steve Chang
on 9 Oct 2018
Walter Roberson
on 10 Oct 2018
continue is going to proceed to the next parfor iteration -- without having executed the assignment to values{i} that is after the continue.
Steve Chang
on 10 Oct 2018
Edric Ellis
on 11 Oct 2018
There's an existing problem in the parfor machinery that causes the values assignment to fail. The problem relates to the combination of try / catch and the assignment to values. You can trick the parfor machinery into operating correctly by changing how it analyses values. The following should work:
N = 1000;
failed = false( 1, N );
values = cell( 1, N );
n_failed = 0;
parfor idx = 1:N
% Dummy reference to "values(idx)":
if false
values(idx);
end
try
if ( rand() > 0.7 )
n_failed = n_failed + 1;
assert(false);
end
catch err
failed(idx) = true;
continue;
end
values{idx} = rand( 1e3, 1 );
end
fprintf( 'N failed 1: %d\n\n', sum(failed) );
fprintf( 'N failed 2: %d\n', n_failed );
Steve Chang
on 11 Oct 2018
Categories
Find more on Data Type Identification 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!