写点什么

讨论:泛型是否会对性能产生负面影响

  • 2009-05-30
  • 本文字数:1861 字

    阅读完需:约 6 分钟

正值端午传统节日,在国内知名的.NET 技术社区博客园中进行了一场较为激烈的讨论。讨论话题围绕:.NET 中的泛型是否会影响性能。

飞林沙的一篇文章《从 dynamic 到特性误用》引起了这场讨论。在这片文章中,飞林沙指出 C# 4.0 新增的 dynamic 关键字会对程序性能的影响,呼吁大家仅在合适的时候使用 dynamic 新特性。可能是由于社区中对于 C# 4.0 的新特性还不太关注,这个问题本身的反响不大。反而是文章所引发的一个周边话题引起了网友的兴趣。

在文章的结尾,飞林沙认为太多开发人员并没有了解新特性的优劣就盲目追逐,并举出他所认为的一个泛型错误做法:

……我看到有人在代码中使用 List而不是 ArrayList,我不明白这种做法除了降低性能之外还有什么好处……

文章发表不久,便有网友对此观点产生质疑,认为“泛型是生成新的类型,拿来的效率影响之说”,不过也有网友表示“.NET 的泛型会略微影响效率,跟 C++ 略有些不同”。在 Jeffrey Zhao 发表了一篇性能比较文章之后,围绕这个话题的讨论便由此展开。

Jeffrey Zhao 的文章《泛型真的会降低性能吗?》使用代码来统计常用操作所消耗的时间,试图发现泛型容器对性能的影响。除了.NET 类库中经典的 ArrayList 和 List类型之外,他还编写了最简单的 MyArrayList 和 MyList两个类型,目的是避免其它任何实现方面的细节对性能的影响。对于长度为 100 的容器,各执行 30 万次操作的结果如下表所示:

使用 for 进行下标遍历 使用 foreach 进行遍历 MyArrayList 2,398ms 21,367ms MyList 2,285ms 3,463ms ArrayList 2,282ms 5,187ms List 2,302ms 2,989ms 根据实验结果,Jeffrey Zhao 得出了以下结论:

……泛型的 MyList 性能甚至略比 MyArrayList 有所提高。当然测试的结果其实是互有胜负,但是事实上,MyList 的获胜的次数甚至还略有领先……从结果上已经可以看出,泛型并不会影响性能,而 List的性能也不比 ArrayList 要差……

Jeffrey Zhao 同时呼吁“在有泛型支持的情况下,尽量使用泛型容器。例如使用 List而不是 ArrayList”:

……除了“性能”之外,老赵的还有其他一些理由。例如使用 List的话就可以使用框架内部所定义的各种有用的辅助方法(要知道在.NET 框架中,现在几乎都是在针对 IEnumerable进行开发);而我们平时写程序时,也可以统一的针对泛型编程,如 IList,IEnumerable,不必考虑 List 或 Enumerable 等非泛型元素。

Jeffrey Zhao 的测试结果得到了大部分网友的承认,不过也有部分网友对这个实验的部分做法有所质疑。如开源框架 NBear 的创始人 Teddy Ma 认为 MyArrayList 的 foreach 操作慢的原因在于非泛型的 IEnumerator 内部对于数组使用 Array.GetValue(Int32) 来获取对象,而泛型的 IEnumerator则直接使用数组下标进行访问:

……如果都用 for 而不是 foreach,我想应该非泛型略快一点点。

对此,Jeffrey Zhao 回应道:

……我测试的都是平时的常用操作,黑盒测试,没有故意去走某个特别慢的路径。……看来内部实现的造成问题,可惜我们平时都是用这个做法,因为是框架自带的。

为什么总是说泛型性能会差一些?测试结果都摆在这里了。根据测试结果,就算是下标访问,泛型也不差。……所以结论还是不变,能够用 List就不要用 ArrayList。

稍后又有网友引用了国外网友 Rico Mariani 的文章回复中总结的观点,认为 ArrayList 比 List性能差的原因在于:

  1. ArrayList 中使用了大量的虚方法,.NET 框架设计团队不反对我们继承 ArrayList 实现新的集合类型。这种做法也影响了 JIT 对方法的内联。
  2. ArrayList 的遍历器实现较为复杂,会构造大量的 Enumerator 对象。而在.NET 2.0 中新设计的 List类型简化了这部分代码,获得了较高的性能。

至此,大家基本已经达成共识,ArrayList 性能较差是由于内部实现逻辑的影响,在实际开发过程中使用 List能够获得更好的性能。不过,还是有一些网友“普遍认为”,抛开泛型对值类型装箱 / 拆箱的性能优化,纯粹的泛型容器性能还是会略低于非泛性的 Object 容器。不过,Jeffrey Zhao 新发表的一篇文章似乎从根本上推翻了这个看法。

在《从汇编入手,探究泛型的性能问题》一文中,Jeffrey Zhao 使用 WinDbg 查看了 MyArrayList 和 MyList的下标 get 方法,在 JIT 之后所生成的汇编代码,并加以详细的分析和对比。比较的结果发现,两者除了几个地址不同之外,在执行时所经过的指令几乎完全相同,以此有力地证明了“泛型并不会影响程序性能”。

在问题的讨论过程中也产生了一些额外的话题,例如究竟应该使用 for 和下标访问,还是 foreach 来遍历一个容器,还有一个应用程序是否应该在这样的地方追求性能提升。

您的看法是什么呢?

2009-05-30 20:193557
用户头像

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

关注

评论

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

基于SLO告警(Part 2):为什么使用MWMB方法

Grafana 爱好者

可观测性 Grafana Prometheus SRE SLO

高效管理,让工作事半功倍

石云升

极客时间 2月月更 技术领导力实战笔记

如何理解DevOps?

老张

DevOps 软件工程

用 NFTScan 的角度解析 Yuga labs NFT 项目系列

NFT Research

NFT BAYC

DataEase 启动异常如何解决:Access denied for user 'root'@'xx.xx.xx.xxx' (using password YES)

搞大屏的小北

DataEase

《流浪地球2》的现实倒影(一):从量子计算机到MOSS

脑极体

量子计算机 小苔藓 流浪地球 MOSS

【FAQ】申请运动健康服务验证环节常见问题及解答

HarmonyOS SDK

HMS Core

数字先锋| 枣庄政务云全新升级,居民办事体验upup!

天翼云开发者社区

AI时代的信息技术部怎么改革?

FN0

小程序 超级app

安全可信| 首批+先进!天翼全栈混合云一举斩获三项可信云评估

天翼云开发者社区

Flomesh Ingress 使用实践(二)TLS 进阶

Flomesh

HTTP ingress Pipy

天翼云以10.2%份额位列中国公有云IaaS+PaaS市场第三

天翼云开发者社区

Java高手速成 | JSP MVC模式项目案例

TiAmo

mvc java; jsp

可变二维码,玩转“码”上时代

旺链科技

区块链 区块链技术 区块链溯源

一文读懂SCADA系统的组件功能及应用

2D3D前端可视化开发

组态软件 工业组态软件 web组态软件 SCADA

一体化移动办公平台,让政企工作更轻松、更便捷

BeeWorks

开年直播 | 博睿数据创始人兼CTO对话InfoQ,聊聊2023年重要战略技术趋势:可观测性

博睿数据

可观测性 博睿数据 媒体声音

专访三维空间雷成老师 | 原来水墨画风格的3D建筑动画可以如此惊艳……

Renderbus瑞云渲染农场

瑞云渲染 3D建筑动画 三维空间

面试官:什么是双亲委派模型?

王磊

java面试

疫情时代的宠儿:抗生素行业,今后何去何从

前嗅大数据

大数据 数据分析 网络爬虫 抗生素

泼辣修图2023官方网页版入口在哪里?

茶色酒

泼辣修图2023

疫情大环境下科技互联网公司开源节流降本增效

laofo

研发效能 降本增效 开源节流

时序电路建模基础

timerring

FPGA

架构杂谈——互联网系统架构演进

小小怪下士

Java 程序员 后端 架构设计

数据结构-Hash常见操作实践

杨充

周鸿祎瞄准中小微客户提供免费SaaS,思路:50万企业×2万年费=100亿补贴

B Impact

跨境SaaS企业“会议营销"实战:立足商机注定平庸,300分客户转不转“MQL"?

B Impact

利用 Addax 异构迁移数据到 Databend

Databend

WorkPlus即时通讯软件,专注于企业信息安全可靠的企业IM

BeeWorks

什么是渲染农场,渲染农场一般怎么收费?

Renderbus瑞云渲染农场

云渲染农场 渲染农场

Spring Boot + WebSocket 实时监控异常

程序员大彬

Java springboot

讨论:泛型是否会对性能产生负面影响_.NET_赵劼_InfoQ精选文章