我在我创建的一个类中有一个属性,它当前有一个与之关联的不必要的get函数。我最初在返回值之前做了有用的事情,但现在我只需要属性值,所以get函数已经减少到了这个:
function value = get.error(obj) value = obj.error; end
现在,看到这段代码完全是多余的,我决定一起删除get函数,但这导致我的代码的一部分中出现令人难以置信的减速,其中'error'属性是反复访问。
在这部分代码中,探查器明确地说缺少的get函数是导致问题的原因(它表示所有的时间都浪费在a'的'end'处。 'for'loop),但当我重新添加功能无用的代码时,性能问题就消失了。
为什么删除这个无用的get函数会减慢我的代码?
编辑:我已经将问题隔离到足以发布一些代码示例。
这是方法调用的虚拟版本,它有以下问题:
这是没有无用getter的代码配置文件:
和魔法无用的吸气剂:
请注意,性能要求如下:
将计算集中我的'pool'对象的某些属性用于任何变量。 'error'属性引起了我的注意,但是在相同情况下所有属性都会出现bug。
计算涉及任何事情,甚至'。* 0'导致这种减速,但设置的单个术语是免费减速的(例如obj.pools(i).delta = obj.pools(i).error)
编辑2:
这是完整的池类;也许它会有所帮助:
classdef pool < handle
properties
name;
unit_count;
activation;
net_input = 0;
%all projections now incoming
projections = [];
error; % same is dEd net for rbp
target;
clamped_error = false;
delta;
clamped_activation = 0; %0 no clamp, 1 soft clamp, 2 hard clamp
copyback = false;
copy_from;
type = 'hidden';
activation_history;
error_history;
end
methods
function obj = pool(name,count,type,copy_from)
obj.name = name;
assignin('caller', name, obj);
obj.unit_count = count;
obj.error = zeros(1,count);
obj.target = zeros(1,count);
obj.delta = zeros(1,count);
obj.activation = zeros(1,count);
obj.net_input = zeros(1,count);
obj.activation_history(:,1) = zeros(1,count);
obj.error_history(:,1) = zeros(1,count);
if nargin > 2
obj.type = type;
if nargin == 4
obj.clamped_activation = 2;
obj.activation = ones(1,count)/2;
obj.copy_from = copy_from;
obj.copyback = true;
end
else
obj.type = 'hidden';
end
switch obj.type
case 'input'
obj.clamped_activation = 2;
case 'output'
obj.clamped_error = true;
case 'bias'
obj.clamped_activation = 2;
obj.activation = 1;
case 'hidden'
end
end
function proj = connect(obj,send_pool,proj_var)
%see if you need a new projection or if the user provided one
if nargin == 2
proj = projection(obj, send_pool);
else
proj = proj_var;
end
obj.projections = [obj.projections struct('from',send_pool,'using',proj)];
end
function value = get.error(obj)
value = obj.error;
end
end
end
答案 0 :(得分:1)
这听起来像Matlab JIT或解释器怪异。
您可能正在查看与MCOS内存管理相关的Matlab错误,如Dataset array indexing is very slow with Statistics Toolbox中所述。在某些情况下,在引用其字段时,该错误看起来会导致虚假的深层复制对象。如果池对象中有单元数组或其他复杂结构,则可能会导致类似行为 - 它们会被复制到新变量中,并且可能会在“结束”处显示释放成本。
我能够在几个Matlab版本中重现类似的令人惊讶的缓慢结果。但是我无法表现出与吸气剂的存在有任何区别。
档案fooclass.m。
classdef fooclass
properties
error = 42;
whatever = 42;
delta = 1;
bigjunk = num2cell(rand(1000,40));
%bigjunk = rand(1000,10000); % non-cell does not cause slowdown
end
methods
% function out = get.error(obj)
% out = obj.error;
% end
end
end
文件looper.m。
classdef looper
properties
pools
end
methods
function obj = looper()
obj.pools = repmat(fooclass(), [1 5]);;
end
function weird(obj)
p = obj.pools;
n = numel(p);
for i = 1:n
dummy = obj.pools(i).error .* 0;
end
end
end
end
重现:
>> lp = looper;
>> tic; for i = 1:100; weird(lp); end; toc
Elapsed time is 0.600428 seconds.
这是我在64位Windows 7上的R2011a(预发行版)。这很慢。时间与bigjunk的大小成正比,而探查者说它几乎都发生在p = obj.pools
行。这表明对象引用导致副本而不是像它应该的那样使用写时复制优化。或者它正在走对象图或其他东西。您的代码可能会发生类似情况。
最好只是将它用于解释怪异,如果它能使你的代码更快,那么将getter留在那里,并在下一个版本中等待修复。听起来值得提交给MathWorks作为错误报告。