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
(даже не выполняя или не сохраняя его аргументы) уже в десять раз дороже, чем executing
pow
, Это верный вывод?
Почему это так?
Это случайно конкретный 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;
}