咨询区

  • Ricky G

我正在给项目做性能和代码优化,比如将重复的代码提炼成到一个可重用的方法中,为了能够达到可重用目的,我用 Func<T> 作为方法参数。

public int Calculate(Func<int> expr){return expr();}

当我用 Benchmark 对优化前和优化后的代码做基准测试时,居然发现优化后的在性能上慢了两倍?

完整的代码如下:


using System;
using System.Runtime.CompilerServices;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Exporters;
using BenchmarkDotNet.Loggers;
using BenchmarkDotNet.Running;namespace ConsoleApp1
{class Program{static void Main(string[] args){var summary = BenchmarkRunner.Run<Calculations>();var logger = ConsoleLogger.Default;MarkdownExporter.Console.ExportToLog(summary, logger);Console.WriteLine(summary);}}public class Calculations{public Random RandomGeneration = new Random();[Benchmark]public void CalculateNormal(){var s =  RandomGeneration.Next() * RandomGeneration.Next();}[Benchmark]public void CalculateUsingFunc(){Calculate(() => RandomGeneration.Next() * RandomGeneration.Next());}[MethodImpl(MethodImplOptions.AggressiveInlining)]public int Calculate(Func<int> expr){return expr();}}
}

回答区

  • Jon Skeet

慢两倍的真正原因在于你的每一次调用都会生成一个新的 delegate,所以我一点都不感到惊讶。

如果你的 lambda 表达式不需要捕获 this 或者其他 local 变量,那你完全可以将其提取成一个单例形式,这样就可以避免每一次都调用new了,开销自然就大大减少了。

下面是我修改后的代码:


public class Calculations
{public Random RandomGeneration = new Random();private Func<int> exprField;public Calculations(){exprField = () => RandomGeneration.Next() * RandomGeneration.Next();}[Benchmark]public void CalculateNormal(){var s =  RandomGeneration.Next() * RandomGeneration.Next();}[Benchmark]public void CalculateUsingFunc(){Calculate(() => RandomGeneration.Next() * RandomGeneration.Next());}[Benchmark]public void CalculateUsingFuncField(){Calculate(exprField);}[MethodImpl(MethodImplOptions.AggressiveInlining)]public int Calculate(Func<int> expr){return expr();}
}

benchmark 结果。


|                  Method |     Mean |    Error |   StdDev |
|------------------------ |---------:|---------:|---------:|
|         CalculateNormal | 27.61 ns | 0.438 ns | 0.388 ns |
|      CalculateUsingFunc | 48.74 ns | 1.009 ns | 0.894 ns |
| CalculateUsingFuncField | 32.53 ns | 0.698 ns | 0.717 ns |

虽然还是有一些差距,但相比你的方式已经大大改善了。

点评区

这个确实是在写代码的过程中容易忽视的地方,学习了,用 Benchmark 做基准测试也是值得大家了解的。

为什么我的 Func 如此之慢?相关推荐

  1. 使用.NET中的Action及Func泛型委托

    原文 http://www.cnblogs.com/skm-blog/archive/2013/05/24/3096294.html 委托,在C#编程中占有极其重要的地位,委托可以将函数封装到委托对象 ...

  2. 从 Comparison/Converter 到Func 的进化

    本篇文章给大家介绍两个在.net2.0 中就已经出现的, 很"老"的委托方式. 通常情况下, 我们在Array 和 List<T> 类中使用这些功能. 明白用法和作用可 ...

  3. C#之Action和Func的用法(转自 https://www.cnblogs.com/LipeiNet/p/4694225.html)

    以前我都是通过定义一个delegate来写委托的,但是最近看一些外国人写的源码都是用action和func方式来写,当时感觉对这很陌生所以看起源码也觉得陌生,所以我就花费时间来学习下这两种方式,然后发 ...

  4. [C#基础]Func和Action学习

    目录 委托 Action Func 总结 委托 委托的那些事 关于委托的基本定义,在很久之前的这篇文章中,有个简单的介绍.稍微回顾一下. 委托是c#中类型安全的,可以订阅一个或多个具有相同签名方法的函 ...

  5. 浅谈C#中常见的委托Func,Action,Predicate(转)

    一提到委托,浮现在我们脑海中的大概是听的最多的就是类似C++的函数指针吧,呵呵,至少我的第一个反应是这样的. 关于委托的定义和使用,已经有诸多的人讲解过,并且讲解细致入微,尤其是张子阳的那一篇.我就不 ...

  6. 解决 EF whereT(func) 查询的一个性能问题

    前两年帮朋友 做了个网吧管理软件,采用动软的三层架构 sql语句生成的.最近因功能变更 要改动,而我这段正在做asp.net mvc +ef+autofac的一个电商网站.索性 就把原来的底层全重新了 ...

  7. Delegate,Action,Func,匿名方法,匿名委托,事件

    一.委托Delegate 一般的方法(Method)中,我们的参数总是string,int,DateTime...这些基本的数据类型(或者没有参数),比如 [c-sharp] view plainco ...

  8. C#之Action和Func的用法

    以前我都是通过定义一个delegate来写委托的,但是最近看一些外国人写的源码都是用action和func方式来写,当时感觉对这很陌生所以看起源码也觉得陌生,所以我就花费时间来学习下这两种方式,然后发 ...

  9. 七天学习计划_c#_[2][3][4][5]委托、事件、委托与事件的区别、泛型委托、Func\Action\predicate

    由于委托之前的博客已经详细写了,这里就简单的过一遍,复习一下: 了解委托 基于委托开发事件驱动程序变得非常简单. 使用委托可以大大简化多线程编程难度. 理解委托 委托也可以看做成一种数据类型,可以定义 ...

  10. Func与Action

    平时我们如果要用到委托一般都是先声明一个委托类型,比如: private delegate string Say(); string说明适用于这个委托的方法的返回类型是string类型,委托名Say后 ...

最新文章

  1. 安卓从sd引导linux,从android中的adb shell手动挂载SD卡
  2. nokia 基亚 wp 开发中心
  3. 牛客网7-教417题解
  4. 【剑指offer】反转链表
  5. svn cleanup failed–previous operation has not finished; run cleanup if it was interrupted
  6. Java中bytebuffer和string的转换记录
  7. 常用的JS小功能整理
  8. easyui中combotree只能选子选项,父级不被选中
  9. hashcat 基本使用
  10. 99%的程序员都在用Lombok,原理竟然这么简单?我也手撸了一个!
  11. 2017.8.8 loli测试
  12. leetcode题库1314-- 矩阵区域和
  13. java biz层创建代码_BIZ层调试方法
  14. java人脸识别开源算法_开源-人脸识别认证-java封装
  15. css3仿手机版淘宝商品并列显示
  16. 服务器安装cos系统,COS(国产操作系统)安装教程
  17. APK改之理使用技巧
  18. 在龙芯电脑制作 debian 系统(MIPS)
  19. 戴尔服务器安装ESXI
  20. 自定义view从0到1

热门文章

  1. mikrotikROS系统的几种安装方法
  2. linux进程通讯-纯文本文件
  3. 多种方法解决Exchange 2010 EMC批量启用邮箱之后出..
  4. Windows 2003下×××服务器架设攻略
  5. 使用Treeview模拟操作系统的文件系统
  6. 奇迹暖暖服务器不稳定,闪耀暖暖用土豆当服务器?开服仅半小时就崩溃,无数玩家疯狂吐槽...
  7. windows编译libevent时报告“缺少print_winsock_errors.obj”的解决
  8. java爬虫-简单爬取网页图片
  9. android 游戏 重力
  10. 如何使用Windows搜索在任何文件中搜索文本