【问题标题】:Performance of MATLAB's class constantsMATLAB 类常量的性能
【发布时间】:2019-04-24 05:38:19
【问题描述】:

我的代码中有几个辅助函数,对于给定的数值计算,它们会被多次调用。这些辅助函数使用一些常数值进行计算。同一个常量值可能被多个辅助函数使用。

这似乎是define class properties with constant values 的理想方案。不过,我做了一些基准测试,结果让我感到非常惊讶。

以下面的类为例 (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 中访问类常量真的那么慢还是我遗漏了什么?

当我在 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.

不过,没有一个非硬编码版本接近硬编码版本。这是我在工作中仅有的两个 MATLAB 版本,所以我不知道这些年来这是否一直在改进(这与我自己无关,因为无论如何我都无法使用更新的版本)。

CPU 时间对于我正在开发的东西来说是一个非常重要的因素,但如果可以的话,我想避免用硬编码的文字填充代码。类常量不是所谓的避免这种情况的方法吗?

还有什么我可以考虑的吗?

注意:真正的辅助函数每次都会使用不同的参数调用,因此缓存结果对我来说没有帮助。

【问题讨论】:

    标签: matlab class-constants


    【解决方案1】:

    我也遇到过这个问题,如果有什么技巧可以减少访问类对象的开销,我也很想知道。

    如果可以的话,我会尽量减少对象被访问的次数。在您的示例中,我将在开始循环之前访问 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.
    

    【讨论】:

    • 是的,我想我会选择这个或硬编码,这取决于具体情况。其中许多常量仅用于单位转换,因此像val = a * 0.45; % from lb to kg 这样的行仍然非常可读。这些常量也不应该改变,因此必须手动替换这些硬编码值也不是问题。对于更复杂的事情,我想我会将它们作为参数传递。不过,这会比类常量快得多,这有点有趣,我没想到
    猜你喜欢
    • 1970-01-01
    • 2013-03-10
    • 1970-01-01
    • 2016-05-20
    • 2010-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-02
    相关资源
    最近更新 更多