Локальная переменная-член для большого автоматически распределенного массива C ++? - PullRequest
0 голосов
/ 12 марта 2020

У меня есть операция, которая будет многократно вызываться несколько раз в секунду (может быть, десять тысяч) раз, что требовало использования большого 2D-массива. Каждая операция не зависит друг от друга. Есть ли разница в производительности между хранением его как локальной переменной по сравнению с глобальной переменной? Влияет ли многократное распределение и освобождение 2D-массива на производительность и его преимущества?

class ProcessData {
    void update(Data& data) {
       std::array<std::array<int, 10000>, 10000> matrix;
    }
}

Ответы [ 2 ]

3 голосов
/ 12 марта 2020

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

Поскольку операции взаимно независимы, вам нужно распараллелить их, поэтому у вас есть только три варианта, которые будут работать хорошо: переменная члена класса, локальная переменная потока c или автоматическая c переменная. Размер массива составляет 400 МБ (10e3 ^ 2 * 4 = 100e6 * 4), поэтому он просто не будет работать как автоматическая переменная c - у вас обычно не хватает стека.

Таким образом:

class ProcessData {
public:
  static constexpr int N = 10000;
  using Matrix = std::array<std::array<int, N>, N>;
  void update(Data &data) {
    thread_local static Matrix matrix;
    // ...
  }
};

Недостатком является то, что в зависимости от реализации среды выполнения C ++, matrix может быть выделено при запуске каждого потока, и вы не можете wi sh это тот случай, когда на карту поставлено 400 МБ.

Таким образом, вы можете sh выделить его только по требованию:

// .h
class ProcessData {
public:
  static constexpr int N = 10000;
  using Matrix = std::array<std::array<int, N>, N>;
private:
  thread_local static std::unique_ptr<Matrix> matrix;
public:
  void update(Data &data) {
    if (!matrix) matrix.reset(new Matrix);
    //...
  }
};

// .cpp
thread_local std::unique_ptr<ProcessData::Matrix> ProcessData::matrix;

Матрица будет освобождена всякий раз, когда поток заканчивается (например, рабочий поток в пуле потоков), но также может быть явно освобожден: matrix.reset();

0 голосов
/ 12 марта 2020

Во-первых, да, перераспределение массива (особенно одного такого размера) при каждом вызове update() повлечет за собой значительные затраты производительности. Чтобы исправить это, вы можете просто изменить matrix на локальную переменную stati c. Таким образом, он не освобождается в конце каждого вызова функции. Однако это будет означать, что matrix является общим для всех экземпляров ProcessData.

Если это проблема, вы также можете просто сделать эту переменную-член ProcessData. Тогда у каждого экземпляра будет свой matrix

...