QCon北京「鸿蒙专场」火热来袭!即刻报名,与创新同行~ 了解详情
写点什么

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:132945
用户头像

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

关注

评论

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

AI简报-视频去交错(Deinterlance)

AIWeker

人工智能 深度学习 5月月更 去交错

使用APICloud AVM多端框架开发企业移动OA办公的项目实践

YonBuilder低代码开发平台

企业应用 APP开发 APICloud 多端开发 avm.js

等保和分保的区别是什么?哪个更厉害?

行云管家

网络安全 等保 等级保护 分保

「每日一问」并发编程的特性是什么

爱好编程进阶

Java 程序员 后端开发

令人欣慰!阿里大牛把Spring微服务架构设计整理成了500多页文档,真香

爱好编程进阶

Java 程序员 后端开发

厉害了!把 HashMap 剖析的只剩渣了!

爱好编程进阶

Java 程序员 后端开发

大佬总结的4条宝贵经验,送给初入职场的你,从此一飞冲天

爱好编程进阶

Java 程序员 后端开发

一文聊透 Netty IO 事件的编排利器 pipeline | 详解所有 IO 事件的触发时机以及传播路径

bin的技术小屋

网络编程 Netty java netty 5月月更

优化了MYSQL大量写入问题,老板奖励了1000块给我

爱好编程进阶

Java 程序员 后端开发

【刷题第十天】21. 合并两个有序链表

白日梦

5月月更

KeyDB重量发布6.3.0开源版

华为云开发者联盟

redis 开源 多线程 分布式缓存 KeyDB

史上最全图解JVM,京东小哥带你了解性能提升100%背后的秘密武器

爱好编程进阶

Java 程序员 后端开发

摆平各类目标检测识别AI应用,有它就够了!

华为云开发者联盟

计算机视觉 CANN 昇腾 目标检测识别 YoloV3

云计算的云是指什么?最简单的解释是什么?

行云管家

云计算 云服务 私有云 混合云

HTTP请求转发那些事:你可能不知道的Hop-by-hop Headers和End-to-end Headers

华为云开发者联盟

HTTP 请求转发 web 容器 F5

柏拉图会成为元宇宙风险标吗?PlatoFarm的机会很大

西柚子

【Jvm】Jvm类加载机制

爱好编程进阶

Java 程序员 后端开发

JAVA-使用注解实现Excel表头多语言导出

JayJay

5月月更

讨论两种Redis中Token的存储方式

华为云开发者联盟

Token key 存储token userid

“超级计算机”——GPU云服务器

Finovy Cloud

gpu GPU服务器 GPU算力

如何在缺乏商业项目经验的前提下成功通过面试,兼说我如何甄别非商业项目经验

爱好编程进阶

Java 程序员 后端开发

编写自己的 WordPress 模板

海拥(haiyong.site)

WordPress 5月月更

【解决】jsPDF之长图片生成PDF

爱好编程进阶

Java 程序员 后端开发

极光笔记 | 极光基于元数据驱动数据治理浅谈

极光JIGUANG

数据治理 元数据

小型企业需要CRM系统的理由

低代码小观

CRM 企业管理系统 中小企业 CRM系统 客户关系管理系统

批量作业调度引擎 TASKCTL 安装与实例部署

敏捷调度TASKCTL

程序员 DevOps 分布式 ETL 自动化运维

开源生态在中国:播撒种子,待成雨林

科技热闻

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