Подтвердить что ты не робот

MATLAB: проблема производительности с анонимными функциями

Оптимизируя мой код MATLAB, я наткнулся на странную проблему, связанную с анонимными функциями.

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

Я использовал этот (простой) тестовый файл для воспроизведения поведения с Matlab R2010b под 64-разрядной версией Windows 7:

clear all; close all; clc;

% functions
fn1 = @(x) x^2;
fn2 = @(x) double(x^2);

% variables
x = linspace(-100,100,100000);
N = length(x);

%% anonymous function
y = zeros(1,N);
t = tic;
for i=1:N
    y(i) = fn1(x(i));
end
tm.anonymous_1 = toc(t);

%% anonymous function (modified)
y = zeros(1,N);
t = tic;
for i=1:N
    y(i) = fn2(x(i));
end
tm.anonymous_2 = toc(t);

%% print
tm

Полученные результаты:

tm = 

    anonymous_1: 1.0605
    anonymous_2: 0.1217

Как вы можете видеть, первый подход примерно в 10 раз медленнее. Я понятия не имею, что вызывает ускорение/замедление. Я пробовал разные вещи, получая почти одинаковые (быстрые) тайминги:

fn2 = @(x) 1 * x^2;
fn2 = @(x) 0 + x^2;
fn2 = @(x) abs(x^2);
fn2 = @(x) x*x;


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


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

4b9b3361

Ответ 1

Похоже, что в случае "fn2" оптимизатор Matlab может встроить функцию, тогда как в случае "fn1" он не может этого сделать.

Это, вероятно, связано с тем, что Matlab знает о скалярности или сложности или структуре аргумента и возвращаемого значения. Вероятно, это означает, что "i" (аргумент на сайте вызова) обязательно является скалярным, реальным и нестрогим. Учитывая скалярный аргумент, он пытается выяснить поведение функции. В случае оптимизатора "fn2" Matlab статически определяет, что он всегда может вместить все возможные результаты "double()" в целевую переменную "y (i)". По какой-то причине, известной только разработчикам оптимизатора, Matlab не может прийти к такому же выводу для "fn1" . Возможно, есть некоторые неочевидные угловые случаи, или "^" не хватает части метаданных, от которых зависит оптимизатор. Во всяком случае, результат заключается в том, что в случае "fn1" Matlab, по-видимому, повторно оценивает функцию на каждой итерации.

В любом случае, статически оптимизирующие динамические языки - это черное искусство в дизайне компилятора.

Ответ 2

Я считаю, что создание возвращаемого типа функции, не зависящей от ее типов аргументов, облегчает оптимизацию Matlab. Кстати, y = fn1(x); и y = fn2(x); имеют примерно такую ​​же пропорцию в терминах времени выполнения, поэтому эффект аргументов не является скалярным или сложным.