std::packaged_task действительно дорого?

Я удивлен результатами следующего кода, использующего gcc 4.7.2 на Opensuse Linux:

#include <cmath>
#include <chrono>
#include <cstdlib>
#include <vector>
#include <chrono>
#include <iostream>
#include <future>

int main(void)
{
  const long N = 10*1000*1000;
  std::vector<double> array(N);
  for (auto& i : array)
    i = rand()/333.;

  std::chrono::time_point<std::chrono::system_clock> start, end;
  start = std::chrono::system_clock::now();
  for (auto& i : array)
    pow(i,i);
  end = std::chrono::system_clock::now();
  std::chrono::duration<double> elapsed_seconds = end-start;
  std::cout << "elapsed time: " << elapsed_seconds.count() << "s\n";

  start = std::chrono::system_clock::now();
  for (auto& i : array)
    std::packaged_task<double(double,double)> myTask(pow);
  elapsed_seconds = std::chrono::system_clock::now()-start;
  std::cout << "elapsed time: " << elapsed_seconds.count() << "s\n";

  start = std::chrono::system_clock::now();
  for (auto& i : array)
    std::packaged_task<double()> myTask(std::bind(pow,i,i));
  elapsed_seconds = std::chrono::system_clock::now()-start;
  std::cout << "elapsed time: " << elapsed_seconds.count() << "s\n";

  return 0;
}

Результаты выглядят следующим образом (и довольно последовательны среди прогонов):

elapsed time: 0.694315s
elapsed time: 6.49907s
elapsed time: 8.42619s

Если я правильно интерпретирую результаты, просто создаю std::packaged_task (даже не выполняя или не сохраняя его аргументы) уже в десять раз дороже, чем executingpow, Это верный вывод?

Почему это так?

Это случайно конкретный gcc?

1 ответ

Решение

Вы не рассчитываете время выполнения packaged_taskТолько его создание.

std::packaged_task<double(double,double)> myTask(pow);

Это не выполняется myTaskТолько создает это. В идеале вы не должны измерять это, вы должны измерять myTask(i, i), что я сделал, изменив вашу программу на следующее (я удалил измерения с std::bind).

Результаты хуже, чем вы измерили:

timing raw
elapsed time: 0.578244s

timing ptask
elapsed time: 20.7379s

Похоже packaged_taskОни не подходят для повторяющихся небольших задач, накладные расходы, конечно, больше, чем сама задача. Мое прочтение заключается в том, что вы должны использовать их для многозадачного кода в задаче, которая займет больше времени, чем издержки, связанные с вызовом и синхронизацией packaged_task,

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

Для записи вот что я использовал:

#include <cmath>
#include <chrono>
#include <cstdlib>
#include <vector>
#include <chrono>
#include <iostream>
#include <future>
#include <thread>

int main(void)
{
  const long N = 10*1000*1000;
  std::vector<double> array(N);
  for (auto& i : array)
    i = rand()/333.;

  std::cout << "timing raw" << std::endl;
  std::chrono::time_point<std::chrono::system_clock> start, end;
  start = std::chrono::system_clock::now();
  for (auto& i : array)
    pow(i,i);
  end = std::chrono::system_clock::now();
  std::chrono::duration<double> elapsed_seconds = end-start;
  std::cout << "elapsed time: " << elapsed_seconds.count() << "s\n\n";

  std::cout << "timing ptask" << std::endl;
  start = std::chrono::system_clock::now();
  std::packaged_task<double(double,double)> myTask(pow);
  for (auto& i : array)
  {
      myTask(i, i);
      myTask.get_future().wait();
      myTask.reset();
  }
  elapsed_seconds = std::chrono::system_clock::now()-start;
  std::cout << "elapsed time: " << elapsed_seconds.count() << "s\n\n";
  return 0;
}
Другие вопросы по тегам