Parfor waitbar : How to do this more cleanly?
Show older comments
I'm a frequent casual user of parfor loops. Getting a waitbar (progress meter) from parallel code used to involve having to have each thread append to a file to record progress, and there are a number of contributions on the file exchange that do this. It was kinda silly, but it was necessary.
Now that the DataQueue system exists, it should be possible to do this more sensibly. So I went looking for a good waitbar on the File Exchange. And I couldn't find one, so I tried to make my own.
The code below works nicely, but it depends on using three globals - which isn't great, because if those variable names are being used by something else, it's gonna break stuff. Can anybody suggest a better way to do this, preferably not involving globals? Persistent variables should work within update.m, but it's getting the info (waitbar handle and expected number of interations) from create.m to update.m that's stumped me.
There are three functions, all part of the ParWaitbar package. Usage is explained in the first one:
create.m:
function [ q ] = create( n, txt )
%FNPARWAITBAR Produces a waitbar object that works with parfor.
% Relies on globals. Not sure how to avoid this.
% Input:
% n: Number of iterations expected
% txt: Text for the waitbar dialog.
% Output: q: handle for the dataqueue
%
% Usage: [ q ] = ParWaitbar.create( 10, "Predicting earthquakes..." );
% parfor i=1:10
% pause(rand*5); (or do useful stuff)
% send( q, i ); % doesn't matter what's sent (i here). We're just
% counting the items rcvd.
% end
% ParWaitbar.cleanup(q);
global wb; %waitbar handle.
global wb_N; % number of iterations completed
global wb_max; %number of iterations expected
q = parallel.pool.DataQueue;
wb = waitbar( 0, txt );
wb_max = n;
wb_N = 0;
afterEach( q, @ParWaitbar.update );
end
update.m:
function update(~)
global wb; %shoudl have waitbar handle.
global wb_N; % number of iterations completed
global wb_max; %number of iterations expected
wb_N = wb_N + 1;
waitbar( wb_N / wb_max, wb );
end
cleanup.m
function cleanup( q )
% FIXME we're left with q afterwards. Presumably a fn can't delete
% something outside its own scope
global wb; %shoudl have waitbar handle.
global wb_N; % number of iterations completed
global wb_max; %number of iterations expected
close(wb);
delete(q);
clear wb wb_N wb_max q
end
(as an aside, the fact that we're left with q leftover as a "handle to deleted DataQueue" isn't ideal. But that's far less of a problem than the use of globals with fixed names.)
Accepted Answer
More Answers (0)
Categories
Find more on Startup and Shutdown 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!