C++高性能并行编程与优化 - 课件 - 07 深入浅出访存优化内存的空间局域性有关。 缓存行决定数据的粒度(续) • 所以我们设计数据结构时,应该把数据存 储的尽可能紧凑,不要松散排列。最好每 个缓存行里要么有数据,要么没数据,避 免读取缓存行时浪费一部分空间没用。 重新认识结构体 重新认识 AOS * * * * 重新认识 AOS * 0] a[3,0] a[0,0] a[0,1] a[0,2] a[0,3] 全部测试结果 正确的遍历顺序和错误的遍历顺序,速度 相差了 20 倍。其中一部分是因为每个缓存 行只用到了 1/16 造成的,一部分是因为跳 跃的访存让 CPU 没有办法自动预取造成的 。 封装成 ndarray 类 ndarray.h ,同学们可以在作业或 是自己的项目里随意使用。 不要再用 Java 为参数方程,可以生成一 条分形(自相似)的 Z 字型曲线。该曲线的有一个性质,上面两个 (x,y) 坐标相近的点,他们的 t 也相近(大概率)。 • 意义:可以用一维的 t 遍历二维的网格,然后用 mdec(t) 求出要访问 元素的 (x,y) 坐标,这样可以保证的数据在时间 t 上是接近的,同时二 维空间上 (x,y) 也是接近的,有利于访存局域性。 • 莫顿码还可用于构建八叉树、 BVH 等,但不是今天的话题。0 码力 | 147 页 | 18.88 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 17 由浅入深学习 map 容器很多同学会困惑,为什么要设计两套, C++ 他爸是精神分裂症吗? • 恰恰相反, C++ 是中两个函数不论读写都一视同仁: at 总是抛出异常, [] 总是默默创建 。 • 这么看 Python 才是精分:同一个 [] 函数在读取的时候抛出异常,写入的时候又默默创建 。 • 例如:一个同学问小彭老师在干嘛? • 小彭老师说“我在吃答辩。”那么同学认为这个答辩指的是三体动画,小彭老师在看三体动画。 而不会认为小彭老师真的在吃答辩。 • 小彭老师说“我在拉答辩。”那么同学认为这个答辩指的是答辩(物理),小彭老师在上厕所。 而不会认为小彭老师在制作三体动画。 • 所以这位同学是人类思维,相当于 Python 的精分 API 。而如果另一个同学是硬核的计算 机思维,相当于 C++ 的一视同仁 API ,他会以为小彭老师真的在吃答辩。 • 这是通常来说,不过万一小彭老师真的这么重口味在吃答辩呢?要怎么传达这个信息? 的元素类型是…… • pair。 • 可是为什么要用 const K 呢?上节课说了, set 里面的 K 不能改变!一旦改变就会破坏 好不容易排好的顺序,以后再用二分法 find 就找不准了,所以 set 实际上只有 const_iterator 。 • 但是 map 只针对 K 进行排序, V 又不参与排序,完全可以随意改变。因此 C++ 之父 允许 map 0 码力 | 90 页 | 8.76 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 14 C++ 标准库系列课 - 你所不知道的 set 容器list 都可以调用 std::find ( set 则直接提供了 find 作为成员函数,稍后 讨论) set 和 vector 迭代器的不同点 • set 的迭代器对象也重载了 + + 为红黑树的遍历。 • vector 提供了 + 和 += 的重 载,而 set 没有。这是因为 vector 中的元素在内存中是连 续的,可以随机访问。而 set 是不连续的,所以不能随机访 问,只能顺序访问。 true 。 • pairinsert(int val); insert 的第一个返回值:指向插入 / 现有元素的迭代 器 • 其中第一个返回值是一个迭 代器,分两种情况讨论。 • 当向 set 容器添加元素成功 时,该迭代器指向 set 容器 新添加的元素, bool 类型的 值为 true ; • 如果添加失败,即证明原 set 容器中已存有相同的元 ,里面的元素都是完全随机 的顺序,和插入的顺序也不 一样。虽然你可能注意到这 里的刚好和插入的顺序相反 ?巧合而已,具体怎么顺序 是和 glibc 实现有关的。 • set 基于红黑树实现,相当 于二分查找 树, unordered_set 基于散 列哈希表实现,正是哈希函 数导致了随机的顺序。 不同版本的 set 容器比较 类型 去重 有序 查找 插入 vector × × O(n) O(1) 0 码力 | 83 页 | 10.23 MB | 1 年前3
新一代分布式高性能图数据库的构建 - 沈游人可能认识的人 上下游 同爱好的人 亲属关系 … 人与人、企业与企业、企业与人之间的 复杂、潜在关系推导和挖掘 为已有的分析模型增加“关系特征”维 度 客户贡献度 客户信用分 客户忠诚度 客户欺诈分 客户风险度 违约概率 客户资质 … 集团关系 社群关系 欺诈团伙 担保关系 资金圈 / 链 … 设别出带有某种共同特征 的企业或个人群体 舆情传导 营销传导 风险传导 将高维的图信息映射到低维向量中 • 通过图嵌入将客户关系表示为低维向量,可以结合其 他客户行为特征进行机器学习训练 图卷积神经网络 • 对图结构数据进行卷积计算 • 通过已有的企业数据,通过 GCN 进行半监督学习和分 类,预测企业的违约概率 传统的关系型数据库的存储方式丢失了事物之间的关系信息 Relational Table Real World Multi-Context is Preserved with 需要支持各种不同类型的图计算算法 双重执行模式 • 单机和分布式两套计算系统,在不同的使用 环境中都能达到最佳性能 针对常用算法逐个设计优化方案 • 对于常用算法,跳过固定的编程模型,分 别设计最佳的计算方案 • 例如我们自研的 node2vec 采样算法比现 有技术快了 1 个数量级 海致图计算平台特点 AtlasML 极致的性能 • 支持 CPU/GPU 等异构设备训练0 码力 | 38 页 | 24.68 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 02 现代 C++ 入门:RAII 内存管理与 Java , Python 等垃圾回收语言不同, C++ 的 解构函数是显式的,离开作用域自动销毁,毫不含 糊(有好处也有坏处,对高性能计算而言利大于 弊) 如果没有解构函数,则每个带有返回的分 支都要手动释放所有之前的资源 : RAII :异常安全( exception-safe ) C++ 标准保证当异常发生时,会调用已创建对象的解构函数 。 因此 C++ 中没有(也不需要) finally 数一个个赋值给成员。 • 不过初始化列表的构造函数只支持通过 {} 或 = {} 来构造,不支持通过 () 构造。其实是为了向 下兼容 C++98 编译器默认生成的构造函数:初始化列表(初始化一部分,剩余的为默认 值) • 这个编译器自动生成的初始化列表构造函 数,除了可以指定全部成员来构造以外, 还可以指定部分的成员,剩余没指定的保 持默认。 • 不过你得保证那个没指定的有在类成员定 义里写明 原因还是三五法则,如果拷贝了指针,那么就会出现 之前 Vector 那样重复释放( double free )的问题。 解决方案 1 :获取原始指针( C * 这种类型的指针) • 解决这个问题需要分两种情况讨论。 • 第一种是,你的 func() 实际上并不需要 “夺走”资源的占有权( ownership )。比如 刚才这个例子, func() 只是调用了 p 的 某个成员函数而已,并没有接过掌管对象0 码力 | 96 页 | 16.28 MB | 1 年前3
Zadig 面向开发者的云原生 DevOps 平台e r r i t + Z a d i g 方 案 二 : G i t l a b + Z a d i g 非 核 心 服 务 : 采 用 单 分 支 模 型 m a s t e r 发 版 。 核 心 服 务 : 采 用 双 分 支 模 型 : m a s t e r 发 版 测 试 环 境 和 o n l i n e 发 版 生 产 环 境 。 字节跳动 - 飞书场景一:主干开发主干发布 对于新上项目,面对不同的使用场景,需要创建多 条 Jenkins Job ,配置繁琐,维护负担重。 与 传 统 的 业 务 研 发 不 同 , 电 动 汽 车 领 域 呈 现 新 的 软 件 产 品 交 付 形 态 , 交 付 场 景 复 杂 多 变 。 因 为 工 程 化 的 需 求 不 一 致 , 所 以 很 难 给 研 发 提 供 一 个 统 一 的 协 作 平 台 , 面 对 这 样 的 挑 战 ,0 码力 | 59 页 | 81.43 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 10 从稀疏数据结构到量化数据类型bit 存储,一个 char 可以存储 8 个 bit 用 map 来存储 读取:如果不存在,则读到 0 写入:如果不存在,则创建该表项 用 unordered_map 来存储 map 基于红黑树,会按照键值排序,需要键值具有 operator< 重载,复杂度 O(logn) C++11 新增的 unordered_map 基于哈希表,不保证顺序但更高效,需要键值能被哈希,复杂度 O(1) unordered_map 中存储的表项数量,从而减轻哈 希的压力。但意味着键值在空间上需要具有一定的局域性,否 则 会浪费分块中一 部分空间。 然而我们这里是 要用他记录粒子 经过的点,因此 具有一定空间局 域性,能够被分 块优化。 实际上空间局域 性正是稀疏网格 能够实现的一大 前提,稍后详细 讨论。 在 16x16 分块的基础上,只用一个 bit 存储 图片解释稀疏的好处 传统稠密二维数组 无边界稀疏分块哈希表0 码力 | 102 页 | 9.50 MB | 1 年前3
Rust与算法 - 谢波写作动机 当情况不明时,抱着一个纯粹的目标干事就行了,其他 的留给时间检验。不懂就学,技术写作更像一种共创, 要反复总结和修改 ( 费曼学习法 ) 。 写作本书给我的启示 基础、排序、查找、树、图 代码框、颜色、图片绘制均由 Latex 完成 可参考点 为什么 为什么讲这个话题? 为什么要讲数据结构和算法两部分? 算法相关知识 算法相关知识 • 抽象数据类型 • 时空复杂度 Rust 实现算法 • 蒂姆排序 • 字典树 • 图 Rust 实现算 法 蒂姆排序 什么是蒂姆排序? 蒂姆排序 位运算 高低位排序区别处理 https://github.com/QMHTMY/RustBook/blob/main/publication/code/chapter07/tim_sort_without_gallop.rs 字典树 怎么确定单词结束? 需要区分大小写吗?0 码力 | 28 页 | 3.52 MB | 1 年前3
Await-Tree Async Rust 可观测性的灵丹妙药 - 赵梓淇Poll 的执行逻辑 (Join / Select / Timeout) • 动态的调用关系 • 痛点:观测与调试工具无法理解灵活的执行逻辑 • Backtrace 不够直观 ( 调用栈 -> 调用树 ) • Tracing 无法追踪调用关系的变化 Async Rust 观测与调试的痛点 Async Rust 回顾 • 特性:用户态调度的无栈协程 • Pending Task 不存在栈空间 追踪关键 Future 的生命周期和控制流 • Init, First Poll, Pending, Next Poll, Ready, Cancel • 实时将 Task 的执行状态维护为一棵树 • 显示目前正在阻塞 / 执行的 Await Point • 得名 Await-Tree 基本用例 Await Tree 的设计原理与实现 基本用例 Await Tree 的设计原理与实现 Cancellation Await Tree 的维护 Await Tree 的设计原理与实现 • 下一次 Handle Await Tree 的实现 Await Tree 的设计原理与实现 • 一棵树代表一个 Task 的执行状态 • Task 单线程执行 • 在 Task-Local Storage 中无竞争维护 • 使用 Arena Tree 简化实现 • 无 Unsafe 代码 Await0 码力 | 37 页 | 8.60 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 06 TBB 开启的并行编程之旅就好像是同时运行一样,其实每一时刻只有 一个线程在运行。目的:异步地处理多个不 同的任务,避免同步造成的阻塞。 • 并行:多核处理器,每个处理器执行一个线 程,真正的同时运行。目的:将一个任务分 派到多个核上,从而更快完成任务。 举个例子 • 并发:某互联网公司购置了一台单核处理 器的服务器,他正同时处理 4 个 HTTP 请求,如果是单线程的 listen-accept 循环 他块的慢,而有的块却算得快。但是因为木桶原 理,最后花的时间由最慢的那个线程决定,因此 变成 1 分 30 秒了,多出来的 30 秒里 1 号和 2 号 核心在闲置着,因为任务简单已经算完了,只有 4 号核心一个人在处理额外的光线。 1 2 3 4 1 分 15 秒 1 分 30 秒 0 分 45 秒 0 分 30 秒 解决 1 :线程数量超过 CPU 核心数量,让系统调度保证各个核心始终饱和 tbb::parallel_sort (和标准库串行的 std::sort )加速比: 4.80 倍 重新认识改进的并行缩并 • 其实之前提到“改进后的并行缩并”,也是一 种分治法的思想:大问题一分为二变成小 问题,分派到各个 CPU 核心上,问题足够 小时直接串行求解。 • 他也可以通过 parallel_invoke 分治来实现 : 第 9 章:流水线并行 案例:批量处理数据 注意到这里的0 码力 | 116 页 | 15.85 MB | 1 年前3
共 25 条
- 1
- 2
- 3













