C++高性能并行编程与优化 - 课件 - 06 TBB 开启的并行编程之旅每个任务包含 8 个元素 tbb::static_partitioner ,指定区间的粒度 创建了 2 个线程 2 个任务 每个任务包含 16 个元素 tbb::simple_partitioner 创建了 4 个线程 32 个任务 每个任务包含 1 个元素 tbb::simple_partitioner ,指定区间的粒度 创建了 4 个线程 8 个任务 每个任务包含 4 个元素 tbb::auto_partitioner 记录历史,下次根据经验自动负载均衡 tbb::simple_partitioner 粒度为 1 太细了,效果不好 tbb::static_partitioner 粒度自动变成 n / 4 ,效果好 tbb::simple_partitioner 粒度手动设为 n / 8 ,效果稍微更好一点 tbb::auto_partitioner 自动判断合适的粒度,效果也不错 例子:矩阵转置 使用合适的 grain 大小, 大小, simple_partitioner 比 auto_partitioner 快 3.31 倍 原因 • tbb::simple_partitioner 能够按照给定的粒度 大小( grain )将矩阵进行分块。块内部小区 域按照常规的两层循环访问以便矢量化,块外 部大区域则以类似 Z 字型的曲线遍历,这样 能保证每次访问的数据在地址上比较靠近,并 且都是最近访问过的,从而已经在缓存里可以0 码力 | 116 页 | 15.85 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 07 深入浅出访存优化字节的跨步访问,都会导致数据全部被读取出来。而超过 64 字节的 跨步,则中间的缓存行没有被读取,从而变快了。 缓存行决定数据的粒度 • 结论:访问内存的用时,和访问的字节数 量无关,和访问的每个字节所在的缓存行 数量有关。 • 可见,能否很好的利用缓存,和程序访问 内存的空间局域性有关。 缓存行决定数据的粒度(续) • 所以我们设计数据结构时,应该把数据存 储的尽可能紧凑,不要松散排列。最好每 个缓存行里要么有数据,要么没数据,避 内部是 SOA ,而外部仍是一个 vector的 AOS—— 这种内存布局称为 AOSOA 。 • 缺点是必须保证数量是 1024 的整数倍, 而且因为要两次指标索引,随机访问比较 烦。 • 这里的 1024 并非随意选取,而是要让每 个属性 SOA 数组的大小为一个页 ( 4KB )才能最高效,原因稍后会说明。 AOSOA :注意,内部 SOA 的尺寸不宜太小 SOA 分开存”是没问题的。 • 而且 SOA 在遇到存储不是 vector ,而是稀疏的哈希网格之类索引有一定 开销的数据结构,可能就不适合了。这就是为什么王鑫磊最喜欢 AOSOA :在高层保持 AOS 的统一索引,底层又享受 SOA 带来的矢量化 和缓存行预取等好处……就是随机索引比较麻烦。 结构体剥离: https://blog.csdn.net/qq_36287943/artic 0 码力 | 147 页 | 18.88 MB | 1 年前3
现代C++ 教程:高速上手C++11/14/17/20元组基本操作 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 运行期索引 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 元组合并与遍历 << std::get(t) << std::endl; // 非法, 引发编译期错误 std::cout << std::get<3>(t) << std::endl; 运行期索引 如果你仔细思考一下可能就会发现上面代码的问题,std::get<> 依赖一个编译期的常量,所以下面 的方式是不合法的: int index = 1; std::get (t); new_tuple = std::tuple_cat(get_student(1), std::move(t)); 马上就能够发现,应该如何快速遍历一个元组?但是我们刚才介绍了如何在运行期通过非常数索引 一个 tuple 那么遍历就变得简单了,首先我们需要知道一个元组的长度,可以: template auto tuple_len(T &tpl) { return 0 码力 | 83 页 | 2.42 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 10 从稀疏数据结构到量化数据类型sys/mman.h 头文件里。 • Windows 可以用 VirtualAllocateEx 之类。 • mmap 出来的起始地址保证是对齐到 4KB 的,读写访问其 中偏移地址时,会按页的粒度自动分配和释放内存,从而满 足稀疏数据结构“按需分配”的需求。且由于分页是硬件自动 来做的,比我们软件哈希和指针数组的稀疏更高效,写起来 就和普通的二维数组没什么两样,就好像顺序访问。也用不0 码力 | 102 页 | 9.50 MB | 1 年前3
Hello 算法 1.0.0b4 C++版某些算法的时间复杂度不是固定的,而是与输入数据的分布有关。例如,假设输入一个长度为 ? 的数组 nums ,其中 nums 由从 1 至 ? 的数字组成,但元素顺序是随机打乱的;算法的任务是返回元素 1 的索引。我们可 以得出以下结论: ‧ 当 nums = [?, ?, ..., 1] ,即当末尾元素是 1 时,需要完整遍历数组,此时达到 最差时间复杂度 ?(?) 。 ‧ 当 nums = [1, shuffle(nums.begin(), nums.end(), default_random_engine(seed)); return nums; } /* 查找数组 nums 中数字 1 所在索引 */ int findOne(vector&nums) { for (int i = 0; i < nums.size(); i++) { // 当元素 1 在数组头部时,达到最佳时间复杂度 度」可以体现算法在随机输入数据下 的运行效率,用 Θ 记号来表示。 对于部分算法,我们可以简单地推算出随机数据分布下的平均情况。比如上述示例,由于输入数组是被打乱 的,因此元素 1 出现在任意索引的概率都是相等的,那么算法的平均循环次数则是数组长度的一半 ? 2 ,平均 时间复杂度为 Θ(? 2) = Θ(?) 。 但在实际应用中,尤其是较为复杂的算法,计算平均时间复杂度比较困难,因为很难简便地分析出在数据分 0 码力 | 343 页 | 27.39 MB | 1 年前3
Hello 算法 1.1.0 C++ 版算法的时间效率往往不是固定的,而是与输入数据的分布有关。假设输入一个长度为 ? 的数组 nums ,其中 nums 由从 1 至 ? 的数字组成,每个数字只出现一次;但元素顺序是随机打乱的,任务目标是返回元素 1 的 索引。我们可以得出以下结论。 ‧ 当 nums = [?, ?, ..., 1] ,即当末尾元素是 1 时,需要完整遍历数组,达到最差时间复杂度 ?(?) 。 ‧ 当 nums = [1, ?, ? default_random_engine(seed)); 第 2 章 复杂度分析 hello‑algo.com 41 return nums; } /* 查找数组 nums 中数字 1 所在索引 */ int findOne(vector&nums) { for (int i = 0; i < nums.size(); i++) { // 当元素 1 在数组头部时,达到最佳时间复杂度 杂度可以体现算法在随机输入数据下的 运行效率,用 Θ 记号来表示。 对于部分算法,我们可以简单地推算出随机数据分布下的平均情况。比如上述示例,由于输入数组是被打乱 的,因此元素 1 出现在任意索引的概率都是相等的,那么算法的平均循环次数就是数组长度的一半 ?/2 ,平 均时间复杂度为 Θ(?/2) = Θ(?) 。 但对于较为复杂的算法,计算平均时间复杂度往往比较困难,因为很难分析出在数据分布下的整体数学期望。 0 码力 | 379 页 | 18.47 MB | 1 年前3
Hello 算法 1.0.0b2 C++版某些算法的时间复杂度不是恒定的,而是与输入数据的分布有关。举一个例子,输入一个长度为 ? 数组 nums , 其中 nums 由从 1 至 ? 的数字组成,但元素顺序是随机打乱的;算法的任务是返回元素 1 的索引。我们可以得 出以下结论: ‧ 当 nums = [?, ?, ..., 1],即当末尾元素是 1 时,则需完整遍历数组,此时达到 最差时间复杂度 ?(?) ; ‧ 当 nums = [1, shuffle(nums.begin(), nums.end(), default_random_engine(seed)); return nums; } /* 查找数组 nums 中数字 1 所在索引 */ int findOne(vector& nums) { for (int i = 0; i < nums.size(); i++) { // 当元素 1 在数组头部时,达到最佳时间复杂度 的 运行效率,用 Θ 记号(Theta Notation)来表示。 对于部分算法,我们可以简单地推算出随机数据分布下的平均情况。比如上述示例,由于输入数组是被打乱 的,因此元素 1 出现在任意索引的概率都是相等的,那么算法的平均循环次数则是数组长度的一半 ? 2 ,平均 时间复杂度为 Θ(? 2) = Θ(?) 。 但在实际应用中,尤其是较为复杂的算法,计算平均时间复杂度比较困难,因为很难简便地分析出在数据分布 0 码力 | 197 页 | 15.72 MB | 1 年前3
Hello 算法 1.0.0 C++版算法的时间效率往往不是固定的,而是与输入数据的分布有关。假设输入一个长度为 ? 的数组 nums ,其中 nums 由从 1 至 ? 的数字组成,每个数字只出现一次;但元素顺序是随机打乱的,任务目标是返回元素 1 的 索引。我们可以得出以下结论。 ‧ 当 nums = [?, ?, ..., 1] ,即当末尾元素是 1 时,需要完整遍历数组,达到最差时间复杂度 ?(?) 。 ‧ 当 nums = [1, ?, ? default_random_engine(seed)); 第 2 章 复杂度分析 hello‑algo.com 41 return nums; } /* 查找数组 nums 中数字 1 所在索引 */ int findOne(vector&nums) { for (int i = 0; i < nums.size(); i++) { // 当元素 1 在数组头部时,达到最佳时间复杂度 杂度可以体现算法在随机输入数据下的 运行效率,用 Θ 记号来表示。 对于部分算法,我们可以简单地推算出随机数据分布下的平均情况。比如上述示例,由于输入数组是被打乱 的,因此元素 1 出现在任意索引的概率都是相等的,那么算法的平均循环次数就是数组长度的一半 ?/2 ,平 均时间复杂度为 Θ(?/2) = Θ(?) 。 但对于较为复杂的算法,计算平均时间复杂度往往比较困难,因为很难分析出在数据分布下的整体数学期望。 0 码力 | 378 页 | 17.59 MB | 1 年前3
Hello 算法 1.0.0b5 C++版算法的时间效率往往不是固定的,而是与输入数据的分布有关。假设输入一个长度为 ? 的数组 nums ,其中 nums 由从 1 至 ? 的数字组成,每个数字只出现一次;但元素顺序是随机打乱的,任务目标是返回元素 1 的 索引。我们可以得出以下结论。 ‧ 当 nums = [?, ?, ..., 1] ,即当末尾元素是 1 时,需要完整遍历数组,达到最差时间复杂度 ?(?) 。 ‧ 当 nums = [1, ?, ? shuffle(nums.begin(), nums.end(), default_random_engine(seed)); return nums; } /* 查找数组 nums 中数字 1 所在索引 */ int findOne(vector&nums) { for (int i = 0; i < nums.size(); i++) { // 当元素 1 在数组头部时,达到最佳时间复杂度 记号来表示。 对于部分算法,我们可以简单地推算出随机数据分布下的平均情况。比如上述示例,由于输入数组是被打乱 第 2 章 复杂度分析 hello‑algo.com 39 的,因此元素 1 出现在任意索引的概率都是相等的,那么算法的平均循环次数就是数组长度的一半 ?/2 ,平 均时间复杂度为 Θ(?/2) = Θ(?) 。 但对于较为复杂的算法,计算平均时间复杂度往往是比较困难的,因为很难分析出在数据分布下的整体数学 0 码力 | 377 页 | 30.69 MB | 1 年前3
Hello 算法 1.0.0b1 C++版某些算法的时间复杂度不是恒定的,而是与输入数据的分布有关。举一个例子,输入一个长度为 ? 数组 nums , 其中 nums 由从 1 至 ? 的数字组成,但元素顺序是随机打乱的;算法的任务是返回元素 1 的索引。我们可以得 出以下结论: ‧ 当 nums = [?, ?, ..., 1],即当末尾元素是 1 时,则需完整遍历数组,此时达到 最差时间复杂度 ?(?) ; ‧ 当 nums = [1, shuffle(nums.begin(), nums.end(), default_random_engine(seed)); return nums; } /* 查找数组 nums 中数字 1 所在索引 */ int findOne(vector& nums) { for (int i = 0; i < nums.size(); i++) { // 当元素 1 在数组头部时,达到最佳时间复杂度 的 运行效率,用 Θ 记号(Theta Notation)来表示。 对于部分算法,我们可以简单地推算出随机数据分布下的平均情况。比如上述示例,由于输入数组是被打乱 的,因此元素 1 出现在任意索引的概率都是相等的,那么算法的平均循环次数则是数组长度的一半 ? 2 ,平均 时间复杂度为 Θ(? 2) = Θ(?) 。 但在实际应用中,尤其是较为复杂的算法,计算平均时间复杂度比较困难,因为很难简便地分析出在数据分布 0 码力 | 187 页 | 14.71 MB | 1 年前3
共 21 条
- 1
- 2
- 3













