Callback slow when large object array loaded into function context
4 visualizaciones (últimos 30 días)
Mostrar comentarios más antiguos
Dale Roberts
el 2 de Abr. de 2019
Comentada: Adam
el 4 de Abr. de 2019
I have a strange performance problem when loading an array of handle objects into a function, then subsequently invoking WindowScrollWheelFcn. When scrolling the wheel quickly, the callback interval is very slow, seriously affecting GUI responsiveness. However, if I pass in the object array to the outer function, the callback gets called much more quickly. I'm not sure why.
I tried to whittle the problem down to some test code here, including a handle class, and a function that creates a figure and callback. I could NOT seem to eliminate the need for the Mouse Wheel callback. I tried timers, and calling the function handle directly, but I could not get the problem to occur. So the best way to see it is to run the little test function below, and scroll the mouse wheel on the figure window.
This is just a basically "empty" handle class, and I provided a Static convenience function to create an array of JustHandle objects, which are returned, and also saved to file JH.MAT.
classdef JustHandle < handle
methods (Static)
% Return an array of JustHandle objects, and also save to file.
function JH=MakeArray(NItems)
JH(NItems) = JustHandle(); % pre-allocae object array.
fprintf('Creating array with %d objects...\n', NItems);
for i=1:NItems
JH(i) = JustHandle();
end
fprintf('Saving to file JH.MAT...\n');
save JH JH
end
end
end
And the function that can either take the JH array as an argument, or load it from the JH.MAT file.
function TestSlowCallback(JH)
if nargin < 1
LD = load('JH.mat');
JH = LD.JH;
end
tic;
FIG=figure(200);
FIG.WindowScrollWheelFcn = @ScrollWheelCallback;
function ScrollWheelCallback(src,evt)
fprintf('In callback %.3f\n', toc); % Show time *BETWEEN* callbacks.
tic
end
end
At the command line, create the JustHandle array file, and call the test function:
JH=JustHandle.MakeArray(200000);
TestSlowCallback; % When called w/out arg, file is loaded, and performance is slow.
TestSlowCallback(JH); % When JH is passed in, performace is MUCH better.
With R2018a, when calling w/out arguments, so that load() is called, I get about 300mSec between calls to the ScrollWheel callback. When passing in JH, I get almost an order of magnitude faster, about 40mSec between calls.
Does anyone have an idea why this might be happening, and how to avoid the problem? I understand that function handles have a context that must be passed around, but I'm curious why the difference between loading and passing - isn't the context the same in both cases?
It does seem a bit quirky and obscure, but I wonder if people are getting bitten by it without realizing.
-----
One final note, if I "do something" with the @ScrollWheelCallbackFcn function handle, like return it from the outer TestSlowCallback() function, the problem goes away! So, I guess I have a workaround for the problem, but it just seems really obscure, and I'm not sure why it changes anything.
Thanks for any enlightenment that anyone can provide.
3 comentarios
Guillaume
el 2 de Abr. de 2019
"The only thing I can see that is different is that in the nested function case you also have LD in the workspace and because it is a nested function it has access to the parent workspace which, in the other case, contains only JH."
Clearing LD inside the if had no effect on performance with my testing, so while I also thought that it may have been the reason, it doesn't appear so.
Respuesta aceptada
Guillaume
el 2 de Abr. de 2019
I suspect you meant
JH=JustHandle.MakeArray(200000);
I can't explain the behaviour, however note that load is known to prevent some optimisations.
Also, if you make the callback a local function instead of a nested function, the problem also goes away
function TestSlowCallback(JH)
if nargin < 1
LD = load('JH.mat');
JH = LD.JH;
end
tic;
FIG=figure(200);
FIG.WindowScrollWheelFcn = @ScrollWheelCallback;
end
%local function instead of nested function
function ScrollWheelCallback(src,evt)
fprintf('In callback %.3f\n', toc); % Show time *BETWEEN* callbacks.
tic
end
4 comentarios
Adam
el 4 de Abr. de 2019
You should always be able to have a local function work where a nested function works, simply by passing in the variables it needs from what would otherwise be the parent workspace.
Más respuestas (0)
Ver también
Categorías
Más información sobre Interactive Control and Callbacks en Help Center y File Exchange.
Productos
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!