exponenta event banner

Избегайте ненужных копий данных

Передача значений функциям

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

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

Копирование при записи

Если функция не изменяет входной аргумент, MATLAB не создает копию значений, содержащихся во входной переменной.

Например, предположим, что в функцию передается большой массив.

A = rand(1e7,1);
B = f1(A);

Функция f1 умножает каждый элемент во входном массиве X около 1.1 и присваивает результат переменной Y.

function Y = f1(X)
Y = X.*1.1; % X is a shared copy of A
end

Поскольку функция не изменяет входные значения, локальная переменная X и переменная A в рабочем пространстве вызывающей стороны используется общий доступ к данным. После f1 выполняется, значения назначены A не изменились. Переменная B в рабочем пространстве вызывающего абонента содержится результат умножения по элементам. Входной сигнал передается по значению. Однако при вызове копирование не выполняется f1.

Функция f2 изменяет свою локальную копию входной переменной, в результате чего локальная копия не используется совместно с входными данными A. Значение X в функции теперь является независимой копией входной переменной A в рабочем пространстве вызывающего абонента. Когда f2 возвращает результат в рабочую область вызывающего абонента, локальную переменную X разрушен.

A = rand(1e7,1);
B = f2(A);
function Y = f2(X)
X = X.*1.1; % X is an independent copy of A
Y = X;      % Y is a shared copy of X
end

Передача входных данных в виде выражений MATLAB

Значение, возвращаемое функцией, можно использовать в качестве входного аргумента другой функции. Например, используйте rand для создания входных данных для функции f2 непосредственно.

B = f2(rand(1e7,1));

Единственная переменная, содержащая значение, возвращаемое rand является временной переменной X в рабочей области функции f2. В рабочей области вызывающей стороны нет общей или независимой копии этих значений. Непосредственно передаваемые выходные сигналы функции экономят время и память, необходимые для создания копии входных значений в вызываемой функции. Этот подход имеет смысл, когда входные значения не используются снова.

Назначение на месте

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

A = f2(A);

Назначение по месту следует описанному выше поведению копирования при записи: изменение значений входных переменных приводит к временной копии этих значений.

MATLAB может применять оптимизации памяти при определенных условиях. Рассмотрим следующий пример. canBeOptimized функция создает большой массив случайных чисел в переменной A. Затем он вызывает локальную функцию fLocal, прохождение A в качестве входных данных и присваивая выходным данным локальной функции одно и то же имя переменной.

function canBeOptimized
A = rand(1e7,1);
A = fLocal(A);
end
function X = fLocal(X)
X = X.*1.1;
end

Потому что вызов локальной функции, A = fLocal(A), присваивает выходные данные переменной A, MATLAB не нужно сохранять исходное значение A во время выполнения функции. Изменения, внесенные в X внутри fLocal не приводят к копированию данных. Назначение X = X.*1.1 изменяет X на месте, без выделения нового массива для результата умножения. Исключение копии в локальной функции экономит память и повышает скорость выполнения больших массивов.

Однако MATLAB не может применить эту оптимизацию, если назначение в локальной функции требует индексирования массива. Например, изменение массива ячеек, созданного в updateCells требуется индексация в массив X в локальной функции gLocal. Закольцованное назначение в форме X{i} = X{i}*1.1 создает копию данных в X{i}. Для каждого элемента массива ячеек имеется две копии в рабочей области gLocal.

function updateCells
C = num2cell(rand(1e7,1));
C = gLocal(C);
end
function X = gLocal(X)
for i = 1:length(X)
    X{i} = X{i}*1.1;
end
end

Действует несколько дополнительных ограничений. MATLAB не может применить оптимизацию памяти, когда можно использовать переменную после того, как функция выдаст ошибку. Поэтому эта оптимизация не применяется в сценариях, в командной строке, в вызовах evalили к коду внутри try/catch блоки. Кроме того, MATLAB не применяет оптимизацию памяти, когда исходная переменная доступна непосредственно во время выполнения вызываемой функции. Например, если fLocal является вложенной функцией, MATLAB не может применить оптимизацию, так как переменные могут совместно использоваться родительской функцией. Наконец, MATLAB не применяет оптимизацию памяти, когда назначенная переменная объявлена глобальной или постоянной.

Отладочный код, использующий назначение на месте

Когда MATLAB применяет оптимизацию на месте к оператору назначения, переменная в левой части назначения устанавливается во временное состояние, которое делает ее недоступной до того, как MATLAB выполнит правую часть оператора назначения. Если MATLAB останавливается в отладчике до того, как результат выполнения правой части инструкции будет назначен переменной, проверка левой переменной может привести к ошибке, указывающей на недоступность переменной.

Например, эта функция имеет несоответствие в измерениях переменных A и B.

function A  = inPlace
A = rand(100);
B = rand(99);
dbstop if error
A = A.*B;
end

Выполнение функции вызывает ошибку и останавливается в отладчике.

inPlace
Matrix dimensions must agree.

Error in inPlace (line 5)
A = A.*B;
 
5   A = A.*B;

Попытка просмотра значения переменной A в режиме отладки приводит к ошибке, так как переменная временно недоступна.

K>> A
Variable "A" is inaccessible. When a variable appears on both sides of
an assignment statement, the variable may become temporarily
unavailable during processing.

Чтобы получить больше гибкости при отладке, выполните рефакторинг кода, чтобы удалить контекстное назначение. Например, назначьте результат другой переменной.

function A  = inPlace
A = rand(100);
B = rand(99);
dbstop if error
% Assign result to C indtead of A
C = A.*B;
A = C;
end

Затем переменная A отображается в отладчике.

Почему Semantics Pass-by-Value

MATLAB использует семантику проходных значений при передаче аргументов функциям и возврате значений из функций. В некоторых случаях переходное значение приводит к копиям исходных значений в вызываемой функции. Тем не менее, семантика сквозной передачи обеспечивает определенные преимущества.

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

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

Обрабатывать объекты

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

Объекты-дескрипторы, производные от handle класс, предоставляющий функциональные возможности, такие как события и прослушиватели, методы деструктора и поддержка динамических свойств.

Дополнительные сведения о значениях и дескрипторах см. в разделах Сравнение классов дескрипторов и значений и Тип используемого класса.

См. также

Связанные темы