C++高性能并行编程与优化 - 课件 - 05 C++11 开始的多线程编程
发生了错误。 • 原来 std::thread 的实现背后是基于 pthread 的。 • 解决: CMakeLists.txt 里链接 Threads::Threads 即可: 有了多线程:异步处理请求 • 有了多线程的话,文件下载和用户交互分 别在两个线程,同时独立运行。从而下载 过程中也可以响应用户请求,提升了体验 。 • 可是发现一个问题:我输入完 pyb 以后, 他的确及时地和我交互了。但是用户交互 std::jthread 类,和 std::thread 不同在于:他的解构函数里会 自动调用 join() 函数,从而保证 pool 解 构时会自动等待全部线程执行完毕。 小彭老师快乐吐槽时间 • 多线程、异步、无阻塞、并发,能提升程序响应速度,对现实世界中的软件工程至关重要 。 • 反面教材: blender 在运行物理解算的时候,界面会卡住,算完一帧后窗口才能刷新一遍 ,导致解算过程中基本别想做事,这一定程度上归功于 节点间的连接,为下一次解算做准备,同时当前已经启动的物理解算还能在后台继续正常 运行。虽然 zeno 也用了 opengl ,但他用多进程成功在 opengl 的百般拖后腿下实现了 并发。 第 2 章:异步 异步好帮手: std::async • std::async 接受一个带返回值的 lambda ,自身返回一个 std::future 对象 。 • lambda 的函数体将在另一个线程里执行0 码力 | 79 页 | 14.11 MB | 1 年前3C++高性能并行编程与优化 - 课件 - 08 CUDA 开启的 GPU 编程
如何从核函数里返回数据? • 我们试着把 kernel 的返回类型声明为 int ,试 图从 GPU 返回数据到 CPU 。 • 但发现这样做会在编译期出错,为什么? • 刚刚说了 kernel 的调用是异步的,返回的时候 ,并不会实际让 GPU 把核函数执行完毕,必须 cudaDeviceSynchronize() 等待他执行完毕(和 线程的 join 很像)。所以,不可能从 kernel 里 测试一下时间 • 使用第六节课中的 ticktock.h 测试一下 CPU 和 GPU 的用时。 • 注意,这里一定要把 TOCK 放到同步之 后。原因之前说过,因为对 GPU 核函数 的调用是异步的,只有 cudaDeviceSynchronize() 以后才真正完 成执行,才能算出真的时间。 • 查看结果,发现 GPU 比 CPU 快了很多 ,这是当然的。 调整参数 • 适当调整板块数量 和第七课提到的循环合并法局部迭代一样的方式 。 • 不过这里改用了 GPU 的板块共享内存,线程之 间自动并行,没有像 CPU 那样用循环。 下一课主题? GPU vs CPU • cudaStream 异步编程(流水线式并行) • Nsight profiler 性能分析(和 Vtune 类似) • texture 与 constant 内存(为啥要他们?) • 动态内存分配( GPU 上调用 malloc/free0 码力 | 142 页 | 13.52 MB | 1 年前3C++高性能并行编程与优化 - 课件 - 06 TBB 开启的并行编程之旅
• 运用多线程的方式和动机,一般分为两种。 • 并发:单核处理器,操作系统通过时间片调 度算法,轮换着执行着不同的线程,看起来 就好像是同时运行一样,其实每一时刻只有 一个线程在运行。目的:异步地处理多个不 同的任务,避免同步造成的阻塞。 • 并行:多核处理器,每个处理器执行一个线 程,真正的同时运行。目的:将一个任务分 派到多个核上,从而更快完成任务。 举个例子 • 并发:某互联网公司购置了一台单核处理 最后只需将 4 个小块拼接起来即可得到完整 的 cornell box 图像。总共只花了 1 分钟。 图形学爱好者:我看中的是多核,目的是加速比,如果是单核,那多线程对我无用! 某互联网公司:我看中的是异步,目的是无阻塞,即使是单核,多线程对我也有用。 因特尔开源的并行编程库: TBB https://link.springer.com/chapter/10.1007%2F978-1-4842-4398-5_20 码力 | 116 页 | 15.85 MB | 1 年前3现代C++ 教程:高速上手C++11/14/17/20
t2(critical_section, 3); t1.join(); t2.join(); return 0; } 7.3 期物 期物(Future)表现为 std::future,它提供了一个访问异步操作结果的途径,这句话很不好理解。 为了理解这个特性,我们需要先理解一下在 C++11 之前的多线程行为。 试想,如果我们的主线程 A 希望新开辟一个线程 B 去执行某个我们预期的任务,并返回我一个结 。 而 C++11 提供的 std::future 简化了这个流程,可以用来获取异步任务的结果。自然地,我们很 容易能够想象到把它作为一种简单的线程同步手段,即屏障(barrier)。 为了看一个例子,我们这里额外使用 std::packaged_task,它可以用来封装任何可以调用的目标, 从而用于实现异步的调用。举例来说: #include#include 0 码力 | 83 页 | 2.42 MB | 1 年前3
共 4 条
- 1