Производительность констант класса MATLAB - PullRequest
0 голосов
/ 21 ноября 2018

У меня есть несколько вспомогательных функций в моем коде, которые вызываются много раз для данного численного расчета.Эти вспомогательные функции используют некоторые постоянные значения для своих расчетов.Одно и то же постоянное значение может использоваться более чем одной вспомогательной функцией.

Это кажется идеальным сценарием для определения свойств класса с постоянными значениями .Тем не менее, я провел несколько тестов производительности и весьма удивлен результатами.

Рассмотрим, например, следующий класс (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

Когда я запускаю speed_tests() на MATLAB R2010b, это то, что я получаю (ваш пробег может отличаться):

>> 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, которые у меня есть на работе, поэтому я не знаю, улучшалось ли это с годами (и это не будет актуально для меня, так как я не смог бы использовать более новые версии в любом случае).

Процессорное время является довольно важным фактором для того, что я разрабатываю, но я хотел бы избежать наполнения кода жестко закодированными литералами, если смогу.Разве классовые константы не предполагаемый способ избежать этого?

Есть ли что-то еще, что я мог бы рассмотреть вместо этого?

Примечание: реальные вспомогательные функции вызываются с разнымиаргументы каждый раз, поэтому кэширование результата не поможет в моем случае.

1 Ответ

0 голосов
/ 21 ноября 2018

Я тоже сталкивался с этой проблемой, если есть способ уменьшить накладные расходы при доступе к объектам класса, я бы тоже хотел знать.

Когда я могу попытаться свести к минимуму количество разк объекту обращаются.В вашем примере я бы использовал 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.
...