《深入浅出MFC》2/e
中文字都看得懂,但是整段落就是不知他到底在说啥!因此看到书的作者是您,感觉上就是 一个品质上的保证,必定二话不说,抱回家啰!虽然眼前用不到,但是翻翻看,大致了解一 下,待有空时或是工作上需要时再好好细读。 网络书局的盛行,让我也开始上网买些书。但是我只敢买像您的书!有品质嘛!其它的可就 不敢直接买啰,总是必須到书局翻翻看,确定一下內容,才可能考虑。 vii 台北市Jedi Your books is 的心境,同时也对我与朋友 之间的讨论做个总结: 「只用一样东西,不明白它的道理,实在不高明」。 祝各位胸中丘壑自成! 侯俊杰 新竹1996.08.15 P.S. 愈来愈多的朋友在网络上与我打招呼,闲聊谈心。有医师、盲生、北京的作家、香港的 读者、从国中到研究所的各级学生。学生的科系范围广到令我惊讶,年龄的范围也大到令我 惊讶。对于深居简出的作家而言,读者群只是一个想象空间,哦,我真有这么多读者吗 案中记录过了。如果是新类别,乖乖地记录其类别名称;如果是旧类别,则以代码表示。 这样可以节省文件大小以及程序用于解析的时间。啊,不要看到文件大小就想到硬盘很 便宜,桌上的一切都将被带到网上,你得想想网络频宽这回事。 还有一个问题。文件的「版本」如何控制?旧版程序读取新版文件,新版程序读取旧版 文件,都可能出状况。为了防弊,最好把版本号码记录上去。最好是每个类别有自己的 版本号码。 下面是新0 码力 | 1009 页 | 11.08 MB | 1 年前3Hello 算法 1.1.0 C++ 版
逐渐变得更加精细和复杂。从巧夺天工的匠人技艺、 到解放生产力的工业产品、再到宇宙运行的科学规律,几乎每一件平凡或令人惊叹的事物背后,都隐藏着精 妙的算法思想。 同样,数据结构无处不在:大到社会网络,小到地铁线路,许多系统都可以建模为“图”;大到一个国家,小 到一个家庭,社会的主要组织形式呈现出“树”的特征;冬天的衣服就像“栈”,最先穿上的最后才能脱下; 羽毛球筒则如同“队列”,一端放入、 逻辑结构揭示了数据元素之间的逻辑关系。在数组和链表中,数据按照一定顺序排列,体现了数据之间的线 性关系;而在树中,数据从顶部向下按层次排列,表现出“祖先”与“后代”之间的派生关系;图则由节点 和边构成,反映了复杂的网络关系。 如图 3‑1 所示,逻辑结构可分为“线性”和“非线性”两大类。线性结构比较直观,指数据在逻辑关系上呈 线性排列;非线性结构则相反,呈非线性排列。 ‧ 线性数据结构:数组、链表、栈、队列、哈希表,元素之间是一对一的顺序关系。 UTF‑8 编码。Rust 也提供了 char 类型,用于表示单个 Unicode 码点。 需要注意的是,以上讨论的都是字符串在编程语言中的存储方式,这和字符串如何在文件中存储或在网络中 传输是不同的问题。在文件存储或网络传输中,我们通常会将字符串编码为 UTF‑8 格式,以达到最优的兼容 性和空间效率。 第 3 章 数据结构 hello‑algo.com 64 3.5 小结 1. 重点回顾0 码力 | 379 页 | 18.47 MB | 1 年前3Hello 算法 1.0.0 C++版
逻辑结构揭示了数据元素之间的逻辑关系。在数组和链表中,数据按照一定顺序排列,体现了数据之间的线 性关系;而在树中,数据从顶部向下按层次排列,表现出“祖先”与“后代”之间的派生关系;图则由节点 和边构成,反映了复杂的网络关系。 如图 3‑1 所示,逻辑结构可分为“线性”和“非线性”两大类。线性结构比较直观,指数据在逻辑关系上呈 线性排列;非线性结构则相反,呈非线性排列。 ‧ 线性数据结构:数组、链表、栈、队列、哈希表,元素之间是一对一的顺序关系。 UTF‑8 编码。Rust 也提供了 char 类型,用于表示单个 Unicode 码点。 需要注意的是,以上讨论的都是字符串在编程语言中的存储方式,这和字符串如何在文件中存储或在网络中 传输是不同的问题。在文件存储或网络传输中,我们通常会将字符串编码为 UTF‑8 格式,以达到最优的兼容 性和空间效率。 第 3 章 数据结构 hello‑algo.com 64 3.5 小结 1. 重点回顾 表。假如我们想实现字符到 ASCII 码的映射,则可以将字符的 ASCII 码值作为索引,对应的元素存放在数组中的对应位置。 ‧ 机器学习:神经网络中大量使用了向量、矩阵、张量之间的线性代数运算,这些数据都是以数组的形式 构建的。数组是神经网络编程中最常使用的数据结构。 ‧ 数据结构实现:数组可以用于实现栈、队列、哈希表、堆、图等数据结构。例如,图的邻接矩阵表示实 际上是一个二维数组。0 码力 | 378 页 | 17.59 MB | 1 年前3Hello 算法 1.2.0 简体中文 C++ 版
逐渐变得更加精细和复杂。从巧夺天工的匠人技艺、 到解放生产力的工业产品、再到宇宙运行的科学规律,几乎每一件平凡或令人惊叹的事物背后,都隐藏着精 妙的算法思想。 同样,数据结构无处不在:大到社会网络,小到地铁线路,许多系统都可以建模为“图”;大到一个国家,小 到一个家庭,社会的主要组织形式呈现出“树”的特征;冬天的衣服就像“栈”,最先穿上的最后才能脱下; 羽毛球筒则如同“队列”,一端放入、 逻辑结构揭示了数据元素之间的逻辑关系。在数组和链表中,数据按照一定顺序排列,体现了数据之间的线 性关系;而在树中,数据从顶部向下按层次排列,表现出“祖先”与“后代”之间的派生关系;图则由节点 和边构成,反映了复杂的网络关系。 如图 3‑1 所示,逻辑结构可分为“线性”和“非线性”两大类。线性结构比较直观,指数据在逻辑关系上呈 线性排列;非线性结构则相反,呈非线性排列。 ‧ 线性数据结构:数组、链表、栈、队列、哈希表,元素之间是一对一的顺序关系。 UTF‑8 编码。Rust 也提供了 char 类型,用于表示单个 Unicode 码点。 需要注意的是,以上讨论的都是字符串在编程语言中的存储方式,这和字符串如何在文件中存储或在网络中 传输是不同的问题。在文件存储或网络传输中,我们通常会将字符串编码为 UTF‑8 格式,以达到最优的兼容 性和空间效率。 第 3 章 数据结构 www.hello‑algo.com 64 3.5 小结 1.0 码力 | 379 页 | 18.48 MB | 10 月前3C++高性能并行编程与优化 - 课件 - 06 TBB 开启的并行编程之旅
1 分钟后 4 个处理器都渲染完毕得到结果。 • 最后只需将 4 个小块拼接起来即可得到完整 的 cornell box 图像。总共只花了 1 分钟。 图形学爱好者:我看中的是多核,目的是加速比,如果是单核,那多线程对我无用! 某互联网公司:我看中的是异步,目的是无阻塞,即使是单核,多线程对我也有用。 因特尔开源的并行编程库: TBB https://link.springer.com/chapter/10 至有牺牲工作复杂度换取时间 复杂度的情形。 • 并行算法的复杂度取决于数据量 n ,还取决于线程数量 c ,比如 O(n/c) 。不过要注意如果线程 数量超过了 CPU 核心数量,通常就无法再加速了,这就是为什么要买更多核的电脑。 • 也有一种说法,认为要用 c 趋向于无穷时的时间复杂度来衡量,比如 O(n/c) 应该变成 O(1) 。 映射( map ) 1 个线程,独自处理 8 个元素的映射,花了 并行和串行的速度比较 如何评价 • 公式:加速比 = 串行用时 ÷ 并行用时 • 理想加速比应该是核心的数量。 • for 部分加速比为 5.98 倍。 • reduce 部分加速比为 10.36 倍。 • 提示:老师的电脑是 6 个物理核心, 12 个逻辑核心。 • 似乎这里 reduce 的加速比是逻辑核心数量,而 for 的加速比是物理核心的数量? • 剧透:因为本例中 reduce0 码力 | 116 页 | 15.85 MB | 1 年前3C++高性能并行编程与优化 - 课件 - 07 深入浅出访存优化
cpu-bound 与 memory-bound • 通常来说,并行只能加速计算的部分,不能加速内存读写的部分 。 • 因此,对 fill 这种没有任何计算量,纯粹只有访存的循环体,并 行没有加速效果。称为内存瓶颈( memory-bound )。 • 而 sine 这种内部需要泰勒展开来计算,每次迭代计算量很大的 循环体,并行才有较好的加速效果。称为计算瓶颈( cpu- bound )。 • 并 指的是分支预测是否成功。 多少计算量才算多? • 看右边的 func ,够复杂了吧?也只是勉勉强强超过一 点内存的延迟了,但在 6 个物理核心上并行加速后, 还是变成 mem-bound 了。 • 加速比: 1.36 倍 • 应该达到 6 倍(物理核心数量)才算理想加速比。 加速曲线 • funcA 用了 2 核就饱和。 • funcB 用了 4 核才饱和。 • funcC 用了 6 核才饱和。 • 时,我们的缓存装不下了,不得不把之前存储 的 a[i] 写回主内存。 • 这种代码在主内存看来, CPU 做的事情相当于:读 + 写,从而 每个元素只需要访问两遍内存。对这种完全 mem-bound 的程 序而言就是加速了 2 倍。 测试结果 可见,能否很好的利用缓存,和程序访问内存的时间局域性有关。 案例:一维 jacobi 迭代 • 一些物理仿真中,常用到这种形式的迭代法: • for (i=0...n)0 码力 | 147 页 | 18.88 MB | 1 年前3C++高性能并行编程与优化 - 课件 - 04 从汇编角度看编译器优化
float 的代码,从而增强你程序的吞吐能力! • 通常认为利用同时处理 4 个 float 的 SIMD 指令可以加速 4 倍。但是如果你的算法不 适合 SIMD ,则可能加速达不到 4 倍;也有因为 SIMD 让访问内存更有规律,节约了指 令解码和指令缓存的压力等原因,出现加速超过 4 倍的情况。 第 1 章:化简 编译器优化:代数化简 编译器优化:常量折叠 编译器优化:举个例子 编译器优化:我毕竟不是万能的 memcpy/memset 的调用,影响 可读性。编译器会自动分析你是在做拷贝 或是清零,并优化成对标准库这俩的调用 。 从 0 到 1024 填充: SIMD 加速 paddd :四个 int 的加法 movdqa :加载四个 int 从 0 到 1024 填充: SIMD 加速(续) 看不懂?小彭老师解析一下。右边是方便大家理解的伪代码: 一次写入 4 个 int ,一次计算 4 个 int 的加法,从而更加高 优化; AOS 便于存储在传统容器; AOSOA 两者得兼!是王鑫磊的最 爱。 缺点:需要两层 for 循环,不利于随机访 问;需要数组大小是 4 的整数倍,不过 可以用边界特判法解决。 测试一下加速了多少倍? 优化前: 优化后: 测试结果 SOA + unroll 的方案,比优化前快了 5 倍 ! 并行情况下最快的也是 SOA 。 单线程的 SOA + unroll 甚至略微超过了并0 码力 | 108 页 | 9.47 MB | 1 年前3C++高性能并行编程与优化 - 课件 - 10 从稀疏数据结构到量化数据类型
• 这是因为 i % 2 的计算时间,完全隐藏在内存 的超高延迟里了。 • 可见,当数据量足够大,计算量却不多时,读写 数据量的大小唯一决定着你的性能。 • 特别是并行以后,计算量可以被并行加速,而访 存却不行。 使用 int8_t :每个占据 1 字节 • 因此我们可以把数据类型变小,这样所需的内存 量就变小,从而内存带宽也可以减小! • 对于右边这种内存瓶颈的循环体,从 4 字节的 100 (看图可知:浮点数在 0 附近精度高) 定点数的好处:用 int16_t 表示 • 转成定点数的一大好处就是可以用任意大小的整数来 存储。这样就节省了一半带宽,从而加速了 2 倍。 能不能再小一点:用 int8_t 表示 • 发现结果不对了……说明 int8_t 太小了(可以容纳 - 128 到 127 ),容纳不下 97*100 这么大的数,发生 了溢出导致结果错误。 的代码。 • 要求:自动扩展边界,按需分配内存,垃圾回收及时释放全零的块,用量化的 bit 压缩空 间,使用 omp 或 tbb 并行,用 accessor 缓存坐标以减轻锁的压力。 • 评分规则:加速了多少倍就是多少分。 感谢观看! by 彭于斌( github@archibate ) 录播: https://space.bilibili.com/ 263032155 课件: https://github0 码力 | 102 页 | 9.50 MB | 1 年前3C++高性能并行编程与优化 - 课件 - 11 现代 CMake 进阶指南
(DEFINED CACHE{x}) 判断是否 存在这个缓存变量,但是 set(CACHE{x} ...) 就不 行。 从 bash 设置环境变量试试看 第 11 章:其他小建议 CCache :编译加速缓存 • 用法:把 gcc -c main.cpp -o main 换成 ccache gcc -c main.cpp -o main 即可 • 在 CMake 中可以这样来启用 ccache (就是给每个编译和链接命令前面加上0 码力 | 166 页 | 6.54 MB | 1 年前3C++高性能并行编程与优化 - 课件 - 08 CUDA 开启的 GPU 编程
因此可以通过网格跨步循环增加每个线程访问 arr 的次数,从而超过共享内存部分的时间。 • 当然也别忘了在 main 中增加 gridDim 的大小。 通过模板函数包装一下 使用板块局部数组(共享内存)来加速数组求和 这就是胡渊鸣所说的 BLS ( block-local storage ) 进一步,当数组非常大,缩减后的数组可以继续递归地用 GPU 求和 • 这是第六课说过的方法。递归地缩并,时间复杂度是0 码力 | 142 页 | 13.52 MB | 1 年前3
共 17 条
- 1
- 2