Избегайте копий массивов в MEX-функциях

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

  • MEX-функция получает доступ к входному массиву, но элементы массива не изменяются.

  • MEX-функция изменяет входной массив, и модифицированный массив возвращен в функцию вызова.

Входной массив, не модифицированный

Эта MEX-функция суммирует элементы входного массива, но не изменяет массив. Присвоение inputs[0] к const matlab::data::TypedArray<double> переменная позволяет вам использовать основанный на области значений for цикл, чтобы суммировать элементы. Определение массива как const гарантирует переменную inArray остается разделяемым с входным массивом.

#include "mex.hpp"
#include "mexAdapter.hpp"

using namespace matlab::data;
using matlab::mex::ArgumentList;

class MexFunction : public matlab::mex::Function {
    ArrayFactory factory;
public:
    void operator()(ArgumentList outputs, ArgumentList inputs) {
    double sm = 0;
    const TypedArray<double> inArray = inputs[0];
    for (auto& elem : inArray) {
        sm += elem;
    }
    outputs[0] = factory.createScalar(sm);
    }
};

После сохранения этого кода в файле (названный addArrayElements.cpp в этом примере), скомпилируйте его с mex функция. Вызовите эту MEX-функцию от MATLAB® с двойным массивом как входной параметр.

mex addArrayElements.cpp
b = addArrayElements([1:1e7]);
b =

        5.0000e+13

Модифицированный входной массив

Эта MEX-функция заменяет отрицательные величины во входном массиве с нулями. Эта операция изменяет входной массив, таким образом, вход не может остаться разделяемым с модифицированным массивом. После проверки входного массива функция не использует inputs[0] снова. Поэтому подтвержденный inputs[0] массив перемещен в matlab::data::TypedArray<double> переменная, чтобы включить использование основанного на области значений for цикл, чтобы изменить элементы массива.

Чтобы предотвратить копию входного массива, переместите input[0] к matlab::data::TypedArray<double> использование std::move(), который подкачивает память, сопоставленную с входным массивом к переменной largeArray.

#include "mex.hpp"
#include "mexAdapter.hpp"

using namespace matlab::data;
using matlab::mex::ArgumentList;

class MexFunction : public matlab::mex::Function {
public:
    void operator()(ArgumentList outputs, ArgumentList inputs) {
        checkArguments(inputs);
        TypedArray<double> largeArray = std::move(inputs[0]);
        for (auto& elem : largeArray) {
            if (elem < 0) {
                elem = 0;
            }
        }
        outputs[0] = largeArray;
    }

    void checkArguments(ArgumentList inputs) {
        std::shared_ptr<matlab::engine::MATLABEngine> matlabPtr = getEngine();
        ArrayFactory factory;

        if (inputs[0].getType() != ArrayType::DOUBLE ||
            inputs[0].getType() == ArrayType::COMPLEX_DOUBLE) {
            matlabPtr->feval(u"error", 0, 
                std::vector<Array>({ factory.createScalar("Incorrect input") }));
        }
    }
};

После сохранения этого кода в файле (названный removeNegativeNumbers.cpp в этом примере), скомпилируйте его с mex функция.

mex removeNegativeNumbers.cpp

Вызовите эту MEX-функцию от функции MATLAB. Повторно присвойте модифицированный массив той же переменной.

function arry = processArray(arry)
    arry = removeNegativeNumbers(arry);
    ....
end
    

Например, вызовите processArray функция с большим массивом, возвращенным MATLAB randn функция.

A = processArray(randn(10000));
min(A(:))

ans =

     0

Похожие темы