Conmajia

Stop stealing sheep!

导航

< 2025年2月 >
26 27 28 29 30 31 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 1
2 3 4 5 6 7 8

你觉得 .NET 性能低可能只是因为你的能力低

by Conmajia
⚠️ 由于安全设置本文互动查询功能已失效


本文赞助者◎梦想起航◎ tzhang Tim 李敏 倾听 metoer

破除现代迷信人人有责.NET的源码点这里 Fork

奇了个怪

.NET作为开发平台来说不可否认是优雅的高效的可是有些人就是看不到它极高的开发效率极短的市场推出时间极强的扩展能力非得在性能上较劲把一帮小萌新忽悠得一说起 .NET就觉着是“慢”“卡”的代名词

这些人总是存在一个思维误区认为程序性能是和语言挂钩的您没事儿吧真要这样数据结构算法这些课早他妈该撤了好吧汽车和飞机速度确实不一样但就算给您一架私人飞机您能给表演表演每天开飞机去买菜任何语言的性能瓶颈大半还是出在使用这语言的身上新手司机开着十辆布加迪也不可能拼过驰骋秋名山的五菱宏光老司机咱们不抬杠今天就只说性能不说开发效率上市速度非要跟我抬杠算上这些可能我的“低性能”产品已经出街了你憋半天憋不出屁的“高性能”产品还在扑街优越个🐔🎱呢

.NET的开发语言一般用C#后边我就不区分 .NETC# 了F# 其实也差不多反正最后都编译成intermediate language可以认为是等价的函数式编程更多的是一种思想这个话题我以后会写实话实说C# 这门编程语言一开始就处于一个挺尴尬的位置性能上C/C++ 在前边拦着应用上JavaPython在后边堵截不上不下.NET玩家心里总憋着股邪火只好左右互搏自娱自乐了

语言的比较

这个问题的根源很大一部分在于很多程序员只会一种语言甚至连这唯一的语言也不够精通所以才会要么看不起别的语言要么埋怨自己这语言性能太弱想要一招鲜吃遍天梦里可以醒来最好还是把这茬给忘了而那些对 .NET一知半解就开始嘲讽的“别的语言”玩家就更别指望他们能理解到其中的精髓了

把自己限制于一种语言的程序员会经常错过其他地方提供的重要机会这样的程序员绝对不会被他们的老板或客户看成是专业领域中的专家

——Oliver Sturm

C# 虽然定位尴尬但是它本身是高度优化的要比性能无非就C/C++ 或者汇编才配跟它比JavaPython这些大家都是IL解释的本是同根生相煎急锤子都不一定能比过C#C系玩家就算了特性使然确实比不过但是事实上优化之后性能也大差不差我马上就能证明这一点最奇怪的就是好多JP玩家居然好意思笑话C# 性能辣鸡完全没意识到自己那惨样儿就好像宋小宝去够姚明手里的球结果潘长江在边儿上笑得挺欢笑您🐴呢和机器码比起来任何使用中间语言虚拟机runtime的语言都有损失这话没人能反驳吧Benchmark一般都是用最耗资源的操作——比如图像处理——来比较这无非就是测试磁盘内存的IO性能呗操作系统最终的性能在那卡着assembly可以达到95%C890%C# 可能亏点儿670%的样子然而这都不是重点重点在于有没有完全利用到语言的全部特性以及那些你认为低效率的算法非要用它们真的大丈夫40米大刀拿来削苹果可能它的性能真的很低吧

我过去的试验

2012年的时候我就测试过用C# GDI+读写bitmap一开始用的常规算法很慢但是经过优化后性能提升了363我也没用别的任何类库还是 .NET 2.0原生您说怎么判断C# 的性能到底是低还是高

▲ 2012 年的测试内容已经丢失我在网上找到的爬虫文章

当时一帮哥们儿看了我的试验都手痒秀了一遍优化
鼠标移到作者名字上可以查看作者信息他们都是真·大神

▼ 各路大神和我试验的结果4096×4096@24bpp反色
编号作者耗时毫秒实现方法平台
a.laviewpbt25汇编 + PowerBasici3 380M/3GB/Win7 32-bit
b.兰征鹏12~19VC++.NET调用SSE指令i7 860/12GB/Win7 64-bit
c.胡飞33重写C# 图像库unsafe指针优于 a
d.Conmajia46原生GDI+unsafe指针a

上面这张表可以看到几种语言的性能是接近相差最大20毫秒C# vs 汇编除了bC++ 加了buff当时i7是顶级CPU换到同平台基本差不多的当技巧和算法都优化到极致之后其实C#VBC++ 的性能非常接近了轻微的差异在大部分场景下几乎是可以忽略的这一点我以前这个试验就是很好的解释计算机技术发展到今天语言的运行效率差异早就可以忽略不计了方法论和算法的才是核心事实上对现代C# 而言提高性能其实挺简单的通过下面的试验你就可以看出来

重新再试验

有人说跟程序员交流不要说那么多话要么秀代码要么秀妹子我只有请出互联网的first lady——瑞典模特Lena Soderberg展示的样本经过了处理Lena的介绍可以看昨天的新闻花花公子的封面女郎计算机图像界的女神显然当年的程序员们也是一手杂志一手纸躲被窝里撸管的主我为什么要说“也”😅
Lena是瑞典拼法Lenna是英文拼法

▲ Lena/Lenna

测试图我用Lena原图超高清3831×8192@24bpp文件大小94.2MB完整的 fuli可以在 lenna.org 下载

曾经这里有张图😄

DIP里最最简单的反色举例同样用C#一个萌新和一个大神分别实现那最后的效率可差老了去了不信咱来试试例子使用的方法仅限演示不代表标准方法也不是我这篇文章要讲述的主题——它只是个例子

萌新的实现单线程managed

虽然有点儿欺负人但它确实是实际存在的现象新手玩家不管是熟练度还是连招都跟老油条没得比

private void invert(Bitmap bmp) {
  Color sc = new Color();
  // 逐像素处理
  for (int i = 0; i < bmp.Width; i++) {
    for (int j = 0; j < bmp.Height; j++) {
      // managed operations
      sc = bmp.GetPixel(i, j);
      bmp.SetPixel(i, j, Color.FromArgb(0xff - sc.R, 0xff - sc.G, 0xff - sc.B));
    }
  }
}

这种做法理论上是没错的也能实现效果就是太慢了于是萌新可能就开始骂街C# 真辣鸡.NET真辣鸡可是这算法就他妈的辣鸡啊这种单线程的managed语法想快它也快不起来啊

▲ 你来告诉我1个核上慢慢摇性能怎么提起来

大神的实现并行计算unsafe

大神之所以能叫大神因为他们可以利用语言以及计算机全部实力思路上他们能够选用最佳的合适算法技巧上他们可以挖掘电脑的所有潜力同样的语言不同的性能我再次提出那个问题你说瓶颈在语言还是在人

private void invert(Bitmap bmp) {
  BitmapData bdata = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, bmp.PixelFormat);
  Parallel.ForEach(Partitioner.Create(0, bdata.Height), (H) => {
    unsafe {
      int x, y, w, h, s;
      byte * s0, p;
      w = bdata.Width;
      h = bdata.Height;
      s = bdata.Stride;
      s0 = (byte * ) bdata.Scan0;
      // 逐像素处理
      for (y = H.Item1; y < H.Item2; y++) {
        p = s0 + y * s;
        // unsafe pointer write operations
        for (x = 0; x < w; x++) {
          * p = (byte)(0xff - * p);
          p++;* p = (byte)(0xff - * p);
          p++;* p = (byte)(0xff - * p);
          p++;
        }
      }
    }
  });
  bmp.UnlockBits(bdata);
}

注意这个实现用到了并行计算没有用SetPixel而是直接用指针操作的虽然有点像C/C++但是依然属于原生C# 的范畴可是我不会逐条讲解为什么用了这些技术性能就可以提高我这文章的主题不是教你怎么用Parallel或者给你对比单线程和多线程的性能差而是演示给你看初哥和大手子能轻易拉开多大的距离以此反驳那些动不动觉得某某语言性能不行的门外汉我可不负责科普教学那是你自己解决的事儿

萌新 vs 大神

▲ 同一种语言同一个任务

看看结果吧42466ms对上101ms420的差距谁跟我说 .NET性能差来着请大点儿声谢谢🙏

完毕

其实就上面的例子来说还能把性能再往上提但这都是次要的我想表达的意思已经表达完了.NET的性能并不低如果你觉得低那可能是因为你的能力低

The End.

僵尸兴奋地打开了你的头盖骨又失望地走开了旁边的屎壳郎眼前一亮

posted on2019-02-19   Conmajia  阅读(11051)  评论(83编辑  收藏  举报

编辑推荐:
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
点击右上角即可分享
微信分享提示