并行模式库PPL应用实战(一):使用task类创建并…
2018-06-17 22:25:56来源:未知 阅读 ()
自 VS2010 起,微软就在 CRT 中集成了并发运行时(Concurrency Runtime),并行模式库(PPL,Parallel Patterns Library)是其中的一个重要组成部分。7 年过去了,似乎大家都不怎么Care这个事情,相关文章少少且多是蜻蜓点水。实际上这个库的设计相当精彩,胜过 C++ 标准库中 future/promise/async 系列许多,所以计划写一个系列探讨 PPL 在实际项目中应用中的各种细节。
好了,从最简单的代码开始,先演示下如何使用 task 类和 lambda 表达式创建一个并行任务:
// final_answer.cpp // compile with: /EHsc #include <ppltasks.h> #include <iostream> using namespace concurrency; using namespace std; int main(int argc, char *argv[]) { task<int> final_answer([] { return 42; }); cout << "The final answer is: " << final_answer.get() << endl; return 0; }
使用 Visual Studio 命令行工具编译
cl /EHsc final_answer.cpp
执行结果为:
The final answer is: 42
task 类的原型如下:
template<typename _ReturnType>
class task;
其模板参数 _ReturnType 是任务返回值类型。 task:get 方法则用于获取返回值,原型如下:
_ReturnType get() const;
task 类的构造函数原型:
template<typename T> __declspec(noinline) explicit task(T _Param);
可以看到这是个模板函数,其参数 _Param 可以是 lambda 表达式、函数对象、仿函数、函数指针等可以以 _Param()
形式调用的类型,或者 PPL 中的 task_completion_event<result_type> 类型。因此可以使用各种灵活的方式构造 task 对象,其中 lambda 表达式无疑是最方便常用的一种。
接下来我们修改上面的程序,打印出线程 id 以便观察并行任务的执行情况。
// final_answer_1.cpp // compile with: /EHsc #include <ppltasks.h> #include <iostream> #include <thread> using namespace concurrency; using namespace std; int main(int argc, char *argv[]) { cout << "Major thread id is: " << this_thread::get_id() << endl; task<int> final_answer([] { cout << "Thread id in task is:" << this_thread::get_id() << endl; return 42; }); cout << "The final answer is: " << final_answer.get() << endl; return 0; }
继续编译执行,得到输出结果:
Major thread id is: 164824
Thread id in task is: 164824
The final answer is: 42
注意两个线程 id 是相同的,很有些意外,任务是在主线程执行的而非预计的其他后台工作线程。实际上这是 PPL 的优化策略造成的。
再修改下程序,在 task 对象构造完成后加一个 sleep 调用挂起当前线程一小段时间:
int main(int argc, char *argv[]) { cout << "Major thread id is: " << this_thread::get_id() << endl; task<int> final_answer([] { cout << "Thread id in task is:" << this_thread::get_id() << endl; return 42; }); this_thread::sleep_for(chrono::milliseconds(1)); cout << "The final answer is: " << final_answer.get() << endl; return 0; }
这次输出结果发生了变化:
Major thread id is: 173404
Thread id in task is: 185936
The final answer is: 42
PPL 使用了一个新的线程执行并行任务,实际上 PPL 是使用了线程池来执行被调度到的任务。
而在上一个程序中,由于没有 sleep,也没有其他耗时的代码,执行到 task::get 方法时并行任务尚未被调度所以直接在当前线程执行该任务,这样就节省了两次线程切换的开销。
MSDN 中对 task::wait 方法的说明:
It is possible for wait to execute the task inline, if all of the tasks dependencies are satisfied, and it has not already been picked up for execution by a background worker.
task::get 方法的内部实现会先调用 task::wait 方法所以有同样的效果。
本章小结:
1. task 类对象构造完成后即可被调度执行;
2. 并行有可能被优化在当前线程执行;
留一个问题,如果 task 对象构造后马上析构,该并行任务是否会被调度执行呢?
本章代码使用 visual studio community 2013 编译调试通过。
本章参考文档:
How to: Create a Task that Completes After a Delay
task Class (Concurrency Runtime)
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
- C++之观察者模式 2020-03-19
- c++之模板模式 2020-03-12
- C++之策略模式 2020-03-12
- CPP 设计模式学习 2020-01-02
- Qt事件分发机制源码分析之QApplication对象构建过程 2019-12-08
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash