textprogress bar in parfor

7 Ansichten (letzte 30 Tage)
Luis
Luis am 9 Aug. 2024
Kommentiert: Luis am 22 Aug. 2024
Hey, this used to work in Matlab 2019b and before, to show a progressbar in a parfor loop:
%% par pool
[~, output] = system('free -b | awk ''/Mem/{print $2}''');
total_memory = str2double(output);
myCluster = min(ceil(total_memory / 1024^2 / 2 / 1000), round(maxNumCompThreads));
if isempty(gcp('nocreate'))
pool=parpool(myCluster,'IdleTimeout', 604800);%1 week
end
nsim = 50
%% -----------------------------------
global P;
P = 1;
DataQueue = parallel.pool.DataQueue;
textprogressbar('start: ');
afterEach(DataQueue, @(ss) textprogressbar(P/nsim*100));
afterEach(DataQueue, @updateP);
parfor i = 1:nsim
send(DataQueue,i);
%someprocess
pause(0.1)
end
textprogressbar(' done')
%------------------------------------
function updateP(~)
global P; %#ok<*GVMIS>
P = P+1;
Now, I updated to 2024a Update 4 (24.1.0.2628055). And even though the parloop runs just fine, the progressbar is never updated.
Here's the code of textprogressbar I took somewhere from around here:
function textprogressbar(c)
% This function creates a text progress bar. It should be called with a
% STRING argument to initialize and terminate. Otherwise the number correspoding
% to progress in % should be supplied.
% INPUTS: C Either: Text string to initialize or terminate
% Percentage number to show progress
% OUTPUTS: N/A
% Example: Please refer to demo_textprogressbar.m
% Author: Paul Proteus (e-mail: proteus.paul (at) yahoo (dot) com)
% Version: 1.0
% Changes tracker: 29.06.2010 - First version
% Inspired by: http://blogs.mathworks.com/loren/2007/08/01/monitoring-progress-of-a-calculation/
%% Initialization
persistent strCR; % Carriage return pesistent variable
% Vizualization parameters
strPercentageLength = 6; % Length of percentage string (must be >5)
strDotsMaximum = 10; % The total number of dots in a progress bar
%% Main
if isempty(strCR) && ~ischar(c),
% Progress bar must be initialized with a string
error('The text progress must be initialized with a string');
elseif isempty(strCR) && ischar(c),
% Progress bar - initialization
% fprintf('%s',c);
tcprintf('green',c);
strCR = -1;
elseif ~isempty(strCR) && ischar(c),
% Progress bar - termination
strCR = [];
% fprintf([c '\n']);
tcprintf('red',[c '\n']);
elseif isnumeric(c)
% Progress bar - normal progress
c = floor(c);
percentageOut = [num2str(c) '%%'];
percentageOut = [percentageOut repmat(' ',1,strPercentageLength-length(percentageOut)-1)];
nDots = floor(c/100*strDotsMaximum);
dotOut = ['[' repmat('.',1,nDots) repmat(' ',1,strDotsMaximum-nDots) ']'];
strOut = [percentageOut dotOut];
% Print it on the screen BAR!!!!
if strCR == -1,
% Don't do carriage return during first run
fprintf(strOut);
% tcprintf('yellow',strOut);
else
% Do it during all the other runs
fprintf([strCR strOut]);
% tcprintf('yellow',[strCR strOut]);
end
% Update carriage return
strCR = repmat('\b',1,length(strOut)-1);
else
% Any other unexpected input
error('Unsupported argument type');
end
%%---------------------------------------------------
function tcprintf(style, fmatString, varargin)
% Uses ANSI escape codes to print colored output when using MATLAB
% from a terminal. If not running in a terminal, or if called by MATLAB's
% datatipinfo function, tcprintf reverts to standard printf. The latter is
% desirable if tcprintf is used within an object's disp() method to avoid
% seeing the ANSI characters here.
%
% The first argument is an style description that consists of space-separated
% words. These words may include:
%
% one of the following colors:
% black, red, green, yellow, blue, purple, cyan, darkGray, lightGray, white
%
% one of the following background colors:
% onBlack, onRed, onGreen, onYellow, onBlue, onPurple, onCyan, onWhite
%
% and any of the following modifiers:
% bright : use the bright (or bold) form of the color, not applicable for
% black, darkGray, lightGray, or white
% underline : draw an underline under each character
% blink : This is a mistake. Please don't use this ever.
%
% Example:
% tcprintf('lightGray onRed underline', 'Message: %20s\n', msg);
%
% Author: Dan O'Shea dan at djoshea.com (c) 2012
%
% Released under the open source BSD license
% opensource.org/licenses/bsd-license.php
if nargin < 2 || ~ischar(style) || ~ischar(fmatString)
error('Usage: tcprintf(style, fmatString, ...)');
end
% determine if we're using
usingTerminal = ~usejava('desktop');
% determine if datatipinfo is higher on the stack. If tcprintf
% is used within an object's disp() method, we don't want to
% use color in the hover datatip or all you'll see are ANSI codes.
stack = dbstack;
inDataTip = ismember('datatipinfo', {stack.name});
if ~usingTerminal || inDataTip
% print the message without color and return
fprintf(fmatString, varargin{:});
return;
end
bright = 1;
[colorName backColorName bright underline blink] = parseStyle(style);
colorCodes = getColorCode(colorName, bright);
backColorCodes = getBackColorCode(backColorName);
codes = [colorCodes; backColorCodes];
if underline
codes = [codes; 4];
end
if blink
codes = [codes; 5];
end
codeStr = strjoin(codes, ';');
% evaluate the printf style message
contents = sprintf(fmatString, varargin{:});
% if the message ends with a newline, we should turn off
% formatting before the newline to avoid issues with
% background colors
if ~isempty(contents) && contents(end) == char(10)
contents = contents(1:end-1);
endOfLine = char(10);
else
endOfLine = '';
end
str = ['\033[' codeStr 'm' contents '\033[0m' endOfLine];
fprintf(str);
end
function [colorName backColorName bright underline blink] = parseStyle(style)
defaultColor = 'white';
defaultBackColor = 'onDefault';
tokens = regexp(style, '(?<value>\S+)[\s]?', 'names');
values = {tokens.value};
if ismember('bright', values)
bright = true;
else
bright = false;
end
if ismember('underline', values)
underline = true;
else
underline = false;
end
if ismember('blink', values)
blink = true;
else
blink = false;
end
% find foreground color
colorList = {'black', 'darkGray', 'lightGray', 'red', 'green', 'yellow', ...
'blue', 'purple', 'cyan', 'lightGray', 'white', 'default'};
idxColor = find(ismember(colorList, values), 1);
if ~isempty(idxColor)
colorName = colorList{idxColor};
else
colorName = defaultColor;
end
% find background color
backColorList = {'onBlack', 'onRed', 'onGreen', 'onYellow', 'onBlue', ...
'onPurple', 'onCyan', 'onWhite', 'onDefault'};
idxBackColor = find(ismember(backColorList, values), 1);
if ~isempty(idxBackColor)
backColorName = backColorList{idxBackColor};
else
backColorName = defaultBackColor;
end
end
function colorCodes = getColorCode(colorName, bright)
switch colorName
case 'black'
code = 30;
bright = 0;
case 'darkGray';
code = 30;
bright = 1;
case 'red'
code = 31;
case 'green'
code = 32;
case 'yellow'
code = 33;
case 'blue'
code = 34;
case 'purple'
code = 35;
case 'cyan'
code = 36;
case 'lightGray'
code = 37;
bright = 0;
case 'white'
code = 37;
bright = 1;
case 'default'
code = 39;
end
if bright
colorCodes = [1; code];
else
colorCodes = [code];
end
end
function colorCodes = getBackColorCode(colorName)
switch colorName
case 'onBlack'
code = 40;
case 'onRed'
code = 41;
case 'onGreen'
code = 42;
case 'onYellow'
code = 43;
case 'onBlue'
code = 44;
case 'onPurple'
code = 45;
case 'onCyan'
code = 46;
case 'onWhite'
code = 47;
case 'onDefault'
code = 49;
end
colorCodes = code;
end
function str = strjoin(strCell, join)
% str = strjoin(strCell, join)
% creates a string by concatenating the elements of strCell, separated by the string
% in join (default = ', ')
%
% e.g. strCell = {'a','b'}, join = ', ' [ default ] --> str = 'a, b'
if nargin < 2
join = ', ';
end
if isempty(strCell)
str = '';
else
if isnumeric(strCell) || islogical(strCell)
% convert numeric vectors to strings
strCell = arrayfun(@num2str, strCell, 'UniformOutput', false);
end
str = cellfun(@(str) [str join], strCell, ...
'UniformOutput', false);
str = [str{:}];
str = str(1:end-length(join));
end
end
  4 Kommentare
Walter Roberson
Walter Roberson am 9 Aug. 2024
Calling afterEach multiple times is correct.
But on the off-chance that the last one is replacing the first, try the debugging move of reversing the order of the two calls and see whether that makes a difference in the results.
Luis
Luis am 22 Aug. 2024
hey, both gave the same results.

Melden Sie sich an, um zu kommentieren.

Akzeptierte Antwort

Madheswaran
Madheswaran am 22 Aug. 2024
Hello Luis,
As you described, the ‘parfor’ loop executes correctly, but the progress bar does not update as expected. I executed your code in MATLAB R2019b and was unable to replicate the issue you described. I noticed you're using multiple 'afterEach' functions, which means multiple functions run after each piece of data is received by the ‘DataQueue’.
With my current understanding, the problem arises due to the order of execution of 'updateP' function and 'textprogressbar' function, as the 'updateP' function is being prioritized. You can confirm this by inserting 'disp' statements within both functions to track their execution.
If your goal is to show the progress bar using the ‘textprogressbar’ function in the ‘parfor’ loop, these changes would help you out:
% ... existing code
function updateProgressBar(nsim)
global P;
P = P + 1;
textprogressbar(P/nsim*100);
end
afterEach(DataQueue, @(ss) updateProgressBar(nsim));
textprogressbar('start: ');
parfor i = 1:nsim
send(DataQueue, i);
%someprocess
pause(0.2);
end
textprogressbar(' done');
% ... existing code
In this updated code, I included the ‘textprogressbar’ function inside your ‘updateP’ function and used just one ‘afterEach’ function to call ‘updateProgressBar’. This way, we avoid issues with the order of execution of the callback functions.
I hope this helps!

Weitere Antworten (0)

Kategorien

Mehr zu Loops and Conditional Statements finden Sie in Help Center und File Exchange

Produkte


Version

R2024a

Community Treasure Hunt

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

Start Hunting!

Translated by