写点什么

PDC 09:PLINQ 使用过程中常见性能问题及应对方案

  • 2009-12-06
  • 本文字数:1817 字

    阅读完需:约 6 分钟

在上月举行的 PDC 09 大会上,微软并行库团队的开发工程师 Igor Ostrovsky 介绍了 PLINQ 的工作原理,以及多核编程中,尤其是在 PLINQ 使用过程中几种常见性能问题及应对方法。Igor 表示,这些性能问题很少在顺序编程中遇到,因此在并行环境中容易被人忽视。

第一个性能问题是内存分配。由于利用了多核 CPU 进行运算,对象分配的速度也加快了。此外,程序中可以还会出现更高频率的字符串连接或装箱操作,这都会使 GC 压力增大。.NET 应用程序所使用的默认 GC 方式为 Concurrent GC,它的性能很高,并且为降低应用程序的延迟作了很多优化。它的最佳使用场景是用户交互式应用,这样可以尽可能避免用户界面的停顿,但是它在长期运行的多核程序中表现并不好。而最终的结果是大量计算时间耗费在 GC 上,此时应用程序算法即便是利用了多个核,也会发现它的伸缩能力受到了 GC 限制。解决这个问题的方法之一是减小内存分配,例如可以使用值类型来代替引用类型。值类型的对象会分配在线程栈而不是堆上,以此避免对 GC 产生压力。第二个方法是在 config 文件中启用 Server GC。使用 Server GC 会改变.NET 分配对象的方式,此时.NET 会为每个核准备不同的堆,并且独立进行垃圾回收。这样在一台 4 核的机器上便可以有 4 个线程同时进行垃圾回收,性能自然也就随着多核而提升了。

第二个性能问题是 CPU 在局部化(Locality)和缓存方面的问题。在流行的多核架构中,每个核都有独立的二级缓存。CPU 并不会缓存单个地址中的数据,而是缓存以 64 字节或 128 字节相邻内存的缓存条目(cache line),因此当某个核改变了内存中的数据时,则其他核中地址相邻的缓存数据也会失效,这样 CPU 每次进行计算时都要从速度较慢的内存中加载数据。这个性能问题的隐蔽之处在于代码中的不同数据——例如同一个数组的不同下标——可能在内存中处在同一个缓存条目中,因此这个问题又被称为错误共享(False Sharing)。Igor 演示了一段性能低下的代码,在这个实现中多个线程会不断读写同一个数组的相邻下标,因此造成了错误共享。Igor 的修改方法是将数据存放在数组中相距较远的下标,甚至是不同的数组中。由于 CPU 的缓存条目大小有限,这种方法可以避免出现错误共享。博客园老赵在《计算机体系结构与程序性能》一文中也提出了一种优化方式,他的做法是尽可能使用局部变量来保存计算过程中的中间值,以此减少对数组的修改操作。由于局部变量分处不同线程的栈空间内,因此地址相距很远,不会造成错误共享问题。当有人问起到这种优化方式是否安全时,Igor 答到,这其实和 CPU 架构的实现方式有很大关系。如果某一天缓存实现变化了,可能这种优化方式会适得其反。不过在目前主流架构中,这样的做法是比较安全的。Igor 补充道,他认为这也是为什么“全自动”并行化那么困难的原因之一,因为在并行环境下影响程序性能的方面实在太多了。

第三个问题在于开发人员倾向于在 PLINQ 中使用大量小粒度的委托来完成工作,此时每个委托的计算任务很小,而委托的执行次数会很多。在计算较长的序列时,小粒度的委托对象也能获得性能提高,但是它会产生额外的负载。例如,MoveNext 和 Current 的调用,以及每个委托的执行性能都和虚方法比较接近。此外,一个较长的输入序列也会受限于内存的吞吐量。因此,Igor 建议开发人员在使用 PLINQ 时尽可能使用计算量较大的委托,以此减少计算主体外的性能开销。

第四和第五问题则与 PLINQ 的实现有关。Igor 表示,PLINQ 可以并行执行所有的 LINQ 查询,但是相对于复杂的 LINQ 查询,PLINQ 能够对简单的 LINQ 操作有更好的优化。因此,Igor 建议开发人员在使用 PLINQ 时可以手动将复杂的 LINQ 表达式拆分为简单的 LINQ 查询,并且只在真正需要大量计算的地方才开始并行化。这种结合顺序执行和并行执行的方式,可以让应用程序的性能达到最优。此外,为不同的输入方式选择不同的分块(partition)策略对性能的影响很大,因此 PLINQ 会对数组和 IList<> 进行静态的分割,而对 IEnumerable<> 集合按实际需求进行划分,而开发人员也可以通过自定义 Partitioner 的方式来指定特别的分割策略。

最后,Igor 强调,使用并行计算进行程序性能优化之前,一定要通过合适的评测方式来找到代码的瓶颈。如果这个瓶颈正符合数据并行(data parallel)模式,那么可以使用 PLINQ 进行性能优化。而优化完成后还需要评测其效果,并使用之前提出的几种方案进行合适的调整。

你可以在 PDC 2009 的网站上浏览或下载本次演讲的完整录像及幻灯片等资源。

2009-12-06 08:133271
用户头像

发布了 157 篇内容, 共 62.1 次阅读, 收获喜欢 6 次。

关注

评论

发布
暂无评论
发现更多内容

ArkTS 应用的代码混淆策略:提升安全性与性能

最新动态

利用NFC增强用户体验:HarmonyOS NEXT的NFC应用指南

最新动态

基于YOLOv8的水体环境监控项目(精准识别水域废弃物与污染物)|完整源码数据集+PyQt5界面+完整训练流程+开箱即用!

申公豹

yolov8

韩国用户遭250余款恶意移动应用窃密勒索

qife122

移动安全 网络犯罪

HarmonyOS NEXT应用元服务开发Intents Kit(意图框架服务)事件推荐接入方案

最新动态

HarmonyOS NEXT 端侧部署基础之 HiAI Foundation Kit

最新动态

Apache Doris 3.0.6 版本发布

SelectDB

Doris 数据导入 LakeHouse 物化视图 数据库 大数据

浏览器插件过度分享隐私问题剖析

qife122

浏览器安全 Wappalyzer

华为鸿蒙 UIAbility 组件:构建用户界面的舞台

最新动态

鸿蒙NEXT开发案例:分贝仪

最新动态

联邦学习中的动态提示调优技术FedDPG

qife122

联邦学习 动态提示

鸿蒙NEXT权限申请全攻略:系统授权与用户授权之道

最新动态

HarmonyOS NEXT自定义数据类型的跨应用协作:实现企业级文档管理

最新动态

鸿蒙 NEXT 安全控件与系统 Picker 深度剖析

最新动态

JAVA高级开发工程师怎么找工作?JAVA工作经验4-5年一般会面试什么问题?

程序员高级码农

Java 程序员 Java 面试

HarmonyOS NEXT元服务开发快速入门案例

最新动态

HarmonyOS NEXT应用元服务开发Intents Kit(意图框架服务)本地搜索接入方案

最新动态

星巴克新加坡站6000美元账户接管漏洞:IDOR漏洞详解

qife122

漏洞挖掘 账户接管

开源版 Coze 和 Dify 的深度技术与架构对比

一支烟花AI

人工智能 智能体 agent dify coze

基于JWT的多租户RAG技术实现解析

qife122

OpenSearch 多租户架构

混合递归架构实现推理速度翻倍的技术解析

qife122

推理优化 Transformer架构

从 ClickHouse、Druid、Kylin 到 Doris:网易云音乐 PB 级实时分析平台降本增效

SelectDB

数据库 kylin 数据分析 Doris 网易云音乐

HarmonyOS NEXT在支付场景中的安全通信设计:基于NFC和Secure Element的数据加密

最新动态

HarmonyOS NEXT方舟数据管理与分布式数据库实战:构建高效同步架构

最新动态

假如你从8月份开始准备Java面试,秋招如何成功上岸互联网大厂?Java面试题及答案分享!

程序员高级码农

Java 程序员

IME Kit入门:HarmonyOS输入法开发概述与基础操作

最新动态

鸿蒙NEXT应用国际化:数字与度量衡格式化

最新动态

华为鸿蒙 Want:应用组件之间信息传递的桥梁

最新动态

SelectDB 在 AWS Graviton ARM 架构下相比 x86 实现 36% 性价比提升

SelectDB

数据分析 AWS arm 数据库查询 SelectDB

1行Python代码,实现PDF的加密、解密

程序员晚枫

Python 开源 PDF

基于物理约束与强化驱动的可解释GRU商品需求预测模型

qife122

机器学习 物理信息神经网络

PDC 09:PLINQ使用过程中常见性能问题及应对方案_.NET_赵劼_InfoQ精选文章