MATLAB: проблема производительности с анонимными функциями - PullRequest
12 голосов
/ 19 марта 2011

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

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

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

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;

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

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

Ответы [ 2 ]

8 голосов
/ 19 марта 2011

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

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

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

0 голосов
/ 22 марта 2011

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

...