MATLAB class 常量的性能
Performance of MATLAB's class constants
我的代码中有几个辅助函数,它们被多次调用以进行给定的数值计算。这些辅助函数使用一些常量值进行计算。多个辅助函数可能会使用相同的常量值。
这似乎是 define class properties with constant values 的理想场景。但是,我做了一些基准测试,结果令我感到非常惊讶。
考虑以下 class 例如 (Consts.m
):
classdef Consts
properties (Constant)
A = 0.5
B = 3
end
properties
VariableA
VariableB
end
methods
function obj = Consts()
obj.VariableA = 0.5;
obj.VariableB = 3;
end
end
end
以及以下文件 (speed_tests.m
):
function speed_tests()
tic;
for i = 1:200000
direct_constant_access(1, 2);
end
fprintf('Direct constant access: ');
toc;
tic;
c = Consts();
for i = 1:200000
passing_extra_obj(1, 2, c);
end
fprintf('Passing extra object: ');
toc;
tic;
for i = 1:200000
persistent_constants(1, 2);
end
fprintf('Persistent constants: ');
toc;
% Let's assume this code is executed at some point externally:
% global A B;
% A = 0.5;
% B = 3;
tic;
for i = 1:200000
defined_globally(1, 2);
end
fprintf('Defined globally: ');
toc;
tic;
for i = 1:200000
hardcoded(1, 2);
end
fprintf('Hardcoded: ');
toc;
tic;
for i = 1:200000
hardcoded_v2(1, 2);
end
fprintf('Hardcoded v2: ');
toc;
end
function val = direct_constant_access(a, b)
val = (a + Consts.A)^2 + log(b * Consts.B);
end
function val = passing_extra_obj(a, b, obj)
val = (a + obj.VariableA)^2 + log(b * obj.VariableB);
end
function val = persistent_constants(a, b)
persistent A B;
if isempty(A)
A = Consts.A^2;
B = Consts.B;
end
val = (a + A)^2 + log(b * B);
end
function val = defined_globally(a, b)
global A B;
val = (a + A)^2 + log(b * B);
end
function val = hardcoded(a, b)
val = (a + 0.5)^2 + log(b * 3);
end
function val = hardcoded_v2(a, b)
A = 0.5;
B = 3;
val = (a + A)^2 + log(b * B);
end
当我在 MATLAB R2010b 上 运行 speed_tests()
时,这是我得到的(你的里程可能会有所不同):
>> speed_tests()
Direct constant access: Elapsed time is 5.973690 seconds.
Passing extra object: Elapsed time is 1.760897 seconds.
Persistent constants: Elapsed time is 1.594263 seconds.
Defined globally: Elapsed time is 1.559441 seconds.
Hardcoded: Elapsed time is 0.673995 seconds.
Hardcoded v2: Elapsed time is 0.661189 seconds.
也许我对其他编程语言太习惯了(真正的常量可能会在编译时简单地被文字替换),但是 在 MATLAB 中访问 class 常量真的很慢或者我我错过了什么?
当我在 MATLAB R2013a(同一台计算机)中尝试相同时,这种直接常量访问似乎已经改进了很多:
>> speed_tests()
Direct constant access: Elapsed time is 2.168146 seconds.
Passing extra object: Elapsed time is 1.593721 seconds.
Persistent constants: Elapsed time is 2.302785 seconds.
Defined globally: Elapsed time is 1.404252 seconds.
Hardcoded: Elapsed time is 0.531191 seconds.
Hardcoded v2: Elapsed time is 0.493668 seconds.
不过,none 的非硬编码版本与硬编码版本接近。这是我在工作中仅有的两个 MATLAB 版本,所以我不知道这些年来它是否一直在改进(而且它与我自己无关,因为无论如何我都无法使用更新的版本)。
CPU 时间对于我正在开发的东西来说是一个非常重要的因素,但如果可以的话,我想避免用硬编码文字填充代码。 class 常数不是所谓的避免这种情况的方法吗?
还有什么我可以考虑的吗?
注意:真正的辅助函数每次都使用不同的参数调用,因此缓存结果对我的情况没有帮助。
我也 运行 研究过这个问题,如果有减少访问 class 对象的开销的技巧,我也很想知道。
什么时候可以尽量减少访问对象的次数。在您的示例中,我会在开始循环之前访问 A 和 B 一次,然后将它们作为参数传递给每个函数调用。
function speed_tests()
tic;
A = Consts.A;
B = Consts.B;
for i = 1:200000
passing_arguments(1, 2, A, B);
end
fprintf('Passing arguments: ');
toc;
tic;
for i = 1:200000
persistent_constants(1, 2);
end
fprintf('Persistent constants: ');
toc;
tic;
for i = 1:200000
hardcoded(1, 2);
end
fprintf('Hardcoded: ');
toc;
end
function val = passing_arguments(a, b, A, B)
val = (a + A)^2 + log(b * B);
end
function val = persistent_constants(a, b)
persistent A B;
if isempty(A)
A = Consts.A^2;
B = Consts.B;
end
val = (a + A)^2 + log(b * B);
end
function val = hardcoded(a, b)
val = (a + 0.5)^2 + log(b * 3);
end
输出:
Passing arguments: Elapsed time is 0.035402 seconds.
Persistent constants: Elapsed time is 0.208998 seconds.
Hardcoded: Elapsed time is 0.027781 seconds.
我的代码中有几个辅助函数,它们被多次调用以进行给定的数值计算。这些辅助函数使用一些常量值进行计算。多个辅助函数可能会使用相同的常量值。
这似乎是 define class properties with constant values 的理想场景。但是,我做了一些基准测试,结果令我感到非常惊讶。
考虑以下 class 例如 (Consts.m
):
classdef Consts
properties (Constant)
A = 0.5
B = 3
end
properties
VariableA
VariableB
end
methods
function obj = Consts()
obj.VariableA = 0.5;
obj.VariableB = 3;
end
end
end
以及以下文件 (speed_tests.m
):
function speed_tests()
tic;
for i = 1:200000
direct_constant_access(1, 2);
end
fprintf('Direct constant access: ');
toc;
tic;
c = Consts();
for i = 1:200000
passing_extra_obj(1, 2, c);
end
fprintf('Passing extra object: ');
toc;
tic;
for i = 1:200000
persistent_constants(1, 2);
end
fprintf('Persistent constants: ');
toc;
% Let's assume this code is executed at some point externally:
% global A B;
% A = 0.5;
% B = 3;
tic;
for i = 1:200000
defined_globally(1, 2);
end
fprintf('Defined globally: ');
toc;
tic;
for i = 1:200000
hardcoded(1, 2);
end
fprintf('Hardcoded: ');
toc;
tic;
for i = 1:200000
hardcoded_v2(1, 2);
end
fprintf('Hardcoded v2: ');
toc;
end
function val = direct_constant_access(a, b)
val = (a + Consts.A)^2 + log(b * Consts.B);
end
function val = passing_extra_obj(a, b, obj)
val = (a + obj.VariableA)^2 + log(b * obj.VariableB);
end
function val = persistent_constants(a, b)
persistent A B;
if isempty(A)
A = Consts.A^2;
B = Consts.B;
end
val = (a + A)^2 + log(b * B);
end
function val = defined_globally(a, b)
global A B;
val = (a + A)^2 + log(b * B);
end
function val = hardcoded(a, b)
val = (a + 0.5)^2 + log(b * 3);
end
function val = hardcoded_v2(a, b)
A = 0.5;
B = 3;
val = (a + A)^2 + log(b * B);
end
当我在 MATLAB R2010b 上 运行 speed_tests()
时,这是我得到的(你的里程可能会有所不同):
>> speed_tests()
Direct constant access: Elapsed time is 5.973690 seconds.
Passing extra object: Elapsed time is 1.760897 seconds.
Persistent constants: Elapsed time is 1.594263 seconds.
Defined globally: Elapsed time is 1.559441 seconds.
Hardcoded: Elapsed time is 0.673995 seconds.
Hardcoded v2: Elapsed time is 0.661189 seconds.
也许我对其他编程语言太习惯了(真正的常量可能会在编译时简单地被文字替换),但是 在 MATLAB 中访问 class 常量真的很慢或者我我错过了什么?
当我在 MATLAB R2013a(同一台计算机)中尝试相同时,这种直接常量访问似乎已经改进了很多:
>> speed_tests()
Direct constant access: Elapsed time is 2.168146 seconds.
Passing extra object: Elapsed time is 1.593721 seconds.
Persistent constants: Elapsed time is 2.302785 seconds.
Defined globally: Elapsed time is 1.404252 seconds.
Hardcoded: Elapsed time is 0.531191 seconds.
Hardcoded v2: Elapsed time is 0.493668 seconds.
不过,none 的非硬编码版本与硬编码版本接近。这是我在工作中仅有的两个 MATLAB 版本,所以我不知道这些年来它是否一直在改进(而且它与我自己无关,因为无论如何我都无法使用更新的版本)。
CPU 时间对于我正在开发的东西来说是一个非常重要的因素,但如果可以的话,我想避免用硬编码文字填充代码。 class 常数不是所谓的避免这种情况的方法吗?
还有什么我可以考虑的吗?
注意:真正的辅助函数每次都使用不同的参数调用,因此缓存结果对我的情况没有帮助。
我也 运行 研究过这个问题,如果有减少访问 class 对象的开销的技巧,我也很想知道。
什么时候可以尽量减少访问对象的次数。在您的示例中,我会在开始循环之前访问 A 和 B 一次,然后将它们作为参数传递给每个函数调用。
function speed_tests()
tic;
A = Consts.A;
B = Consts.B;
for i = 1:200000
passing_arguments(1, 2, A, B);
end
fprintf('Passing arguments: ');
toc;
tic;
for i = 1:200000
persistent_constants(1, 2);
end
fprintf('Persistent constants: ');
toc;
tic;
for i = 1:200000
hardcoded(1, 2);
end
fprintf('Hardcoded: ');
toc;
end
function val = passing_arguments(a, b, A, B)
val = (a + A)^2 + log(b * B);
end
function val = persistent_constants(a, b)
persistent A B;
if isempty(A)
A = Consts.A^2;
B = Consts.B;
end
val = (a + A)^2 + log(b * B);
end
function val = hardcoded(a, b)
val = (a + 0.5)^2 + log(b * 3);
end
输出:
Passing arguments: Elapsed time is 0.035402 seconds.
Persistent constants: Elapsed time is 0.208998 seconds.
Hardcoded: Elapsed time is 0.027781 seconds.