Files
multithread_experiments/experiments/packaged_task.cpp

89 lines
3.1 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include <iostream>
#include <memory>
#include <future>
#include <queue>
/**
* @brief Wrapper for custom invoke operator available function types.
* @note Source from: "Энтони Уильямс, Параллельное программирование на С++ в действии. Практика разработки многопоточных
* программ. Пер. с англ. Слинкин А. А. - M.: ДМК Пресс, 2012 - 672c.: ил." (page 387)
*/
class FunctionWrapper {
struct ImplBase {
virtual void call() = 0;
virtual ~ImplBase() = default;
};
std::unique_ptr<ImplBase> impl;
template<typename F>
struct ImplType: ImplBase {
F f;
explicit ImplType(F&& f): f(std::forward<F>(f)) {}
void call() final { f(); }
};
public:
template<typename F, typename = std::enable_if<!std::is_same<F, FunctionWrapper>::value> >
explicit FunctionWrapper(F&& f): impl(new ImplType<F>(std::forward<F>(f))) {}
void operator()() { impl->call(); }
FunctionWrapper() = default;
FunctionWrapper(FunctionWrapper&& other) noexcept : impl(std::move(other.impl)) {}
FunctionWrapper& operator=(FunctionWrapper&& other) noexcept {
impl = std::move(other.impl);
return *this;
}
FunctionWrapper(const FunctionWrapper&) = delete;
FunctionWrapper& operator=(const FunctionWrapper&) = delete;
};
template<typename Func>
float check_performance(Func test_function) {
auto start = std::chrono::high_resolution_clock::now();
for (int i = 0; i < 5 * 1000 * 1000; ++i) {
test_function();
}
auto end = std::chrono::high_resolution_clock::now();
return std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() / 1000.f;
}
int main() {
std::queue<FunctionWrapper> queue;
queue.push(std::move(FunctionWrapper()));
FunctionWrapper functionWrapper = std::move(queue.front());
queue.pop();
auto test_lambda = [](){ int i = 0; while(i < 100) i++; };
float direct_call_performance = check_performance([&test_lambda](){
std::unique_ptr<std::function<void()> > test_function_p(new std::function<void()>(test_lambda));
test_function_p->operator()();
});
std::cout << "Direct call by pointer: " << direct_call_performance << " ms" << std::endl;
float lambda_wrapper_performance = check_performance([&test_lambda](){
auto copy_lambda = test_lambda;
FunctionWrapper wrapper(std::move(copy_lambda));
wrapper();
});
std::cout << "Lambda with function wrapper: " << lambda_wrapper_performance << " ms" << std::endl;
float std_function_wrapper_performance = check_performance([&test_lambda](){
std::function<void()> test_function(test_lambda);
FunctionWrapper wrapper(std::move(test_function));
wrapper();
});
std::cout << "std function with function wrapper: " << std_function_wrapper_performance << " ms" << std::endl;
float packaged_task_wrapper_performance = check_performance([&test_lambda](){
std::packaged_task<void()> test_packaged_task(test_lambda);
FunctionWrapper wrapper(test_packaged_task);
wrapper();
});
std::cout << "Packaged task with function wrapper: " << packaged_task_wrapper_performance << " ms" << std::endl;
return 0;
}