Эффективное присвоение вектора STL другому вектору STL (выпуск WSL) - PullRequest
0 голосов
/ 12 января 2019

У меня есть проблема, касающаяся времени, в которое выполняется присвоение вектора STL.

Контекст: Я читаю двоичный файл в std::vector, например:

std::vector<float> read_file(const std::string &file_path) {

    std::ifstream stream(file_path);

    if (!stream.good()) {
        std::cout << "Cannot open file located at: " << file_path << std::endl;
        return std::vector<float>();
    }

    stream.seekg(0, std::ios_base::end);    
    auto size = stream.tellg();
    stream.seekg(0, std::ios_base::beg);

    std::vector<float> values(size / sizeof(float));
    stream.read((char*) &values[0], size);

    stream.close();

    return values;
}

У меня есть 128 двоичных файлов , каждый из которых содержит ~ 2.500.000 значений с плавающей запятой .

Со временем у меня будет 128 x std::vector<float> векторов. Однако я хочу, чтобы они хранились в списке / векторе (матрица должна сказать), который превращается в эту структуру данных: std::vector<std::vector<float>>.

Проблема:

Пример 1: Время выполнения этого фрагмента кода займет ~ 700 мс :

std::vector<float> data;
for (int i = 1; i <= 128; ++i) {
    data = read_file(getFile(i));
}

Пример 2: Но время выполнения этого фрагмента кода займет ~ 2000ms :

std::vector<std::vector<float>> data(128);
for (auto i = 1; i <= 128; ++i) {
    data[i-1] = read_file(getFile(i));
}

Насколько я понимаю, назначение будет выполнять операцию перемещения, если правая сторона - vector&&, и операцию копирования, если правая сторона - const vector&. Принимая во внимание RVO, не стоит добавлять std::move к типу возвращаемого значения, поэтому возвращаемое значение не будет скопировано, но перемещено. Однако присваивание в обоих примерах должно делать одно и то же: назначать адрес возвращаемого вектора (правая сторона) для вектора на левой стороне.

Вопрос : Исходя из моего понимания (которое может быть неправильным) и с учетом обоих примеров, почему существует такая большая разница во времени выполнения между Example1 и Example2 , если оба выполняют одну и ту же операцию ( оптимизация была активирована ). Есть ли какие-либо улучшения, которые я могу сделать, чтобы сократить время второго примера? (Я хочу сделать второй пример максимально эффективным)

Спасибо.

Ответы [ 2 ]

0 голосов
/ 15 января 2019

Проблема, которую я обнаружил, - это среда WSL (с помощью которой я компилирую, используя CLion), которая имеет низкую производительность ввода-вывода. Несмотря на то, что я не упомянул этот аспект в своем вопросе, мне пришлось скомпилировать одну и ту же программу на различных платформах и системах, чтобы понять, что именно происходит.

Настройка другой среды здания устранила проблему (время выполнения теперь очень похоже на пример 1 и 2)

0 голосов
/ 12 января 2019

Это не ответ, это способ попытаться понять разницу во времени, но это слишком долго, чтобы быть замечанием

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

Но во втором решении вам нужно в 128 раз больше памяти, может быть, это объясняет разницу во времени? и это применяется, если время выполнения является реальным временем (своп во время выполнения?)

Для сравнения случаев:

int main(int, char ** argv)
{
  switch (*argv[1]) {
  case '1':
    {
      // this is your first case
      std::vector<float> data;
      for (int i = 1; i <= 128; ++i) {
        data = read_file(getFile(i));
      }
    }
    break;
  case '2':
    {
      // this is your seconde case
      std::vector<std::vector<float>> data(128);
      for (auto i = 1; i <= 128; ++i) {
        data[i-1] = read_file(getFile(i));
      }
    }
    break;
  default:
    {
      // this is equivalent to your first case EXCEPT that needs 128 times more memory 
      std::vector<std::vector<float> *> data(128);
      for (auto i = 1; i <= 128; ++i) {
        data[i-1] = new std::vector<float>();
        *(data[i-1]) = read_file(getFile(i));
      }
    }
    break;
  }

  return 0;
}

Когда вы запускаете это с аргументом 3, вы получаете время, когда аргумент равен 1 или 2? Если 2 и 3 похожи, это означает, что необходим больший объем памяти.

...