为什么我的 Func 如此之慢?
咨询区
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 如此之慢?相关推荐
- 使用.NET中的Action及Func泛型委托
原文 http://www.cnblogs.com/skm-blog/archive/2013/05/24/3096294.html 委托,在C#编程中占有极其重要的地位,委托可以将函数封装到委托对象 ...
- 从 Comparison/Converter 到Func 的进化
本篇文章给大家介绍两个在.net2.0 中就已经出现的, 很"老"的委托方式. 通常情况下, 我们在Array 和 List<T> 类中使用这些功能. 明白用法和作用可 ...
- C#之Action和Func的用法(转自 https://www.cnblogs.com/LipeiNet/p/4694225.html)
以前我都是通过定义一个delegate来写委托的,但是最近看一些外国人写的源码都是用action和func方式来写,当时感觉对这很陌生所以看起源码也觉得陌生,所以我就花费时间来学习下这两种方式,然后发 ...
- [C#基础]Func和Action学习
目录 委托 Action Func 总结 委托 委托的那些事 关于委托的基本定义,在很久之前的这篇文章中,有个简单的介绍.稍微回顾一下. 委托是c#中类型安全的,可以订阅一个或多个具有相同签名方法的函 ...
- 浅谈C#中常见的委托Func,Action,Predicate(转)
一提到委托,浮现在我们脑海中的大概是听的最多的就是类似C++的函数指针吧,呵呵,至少我的第一个反应是这样的. 关于委托的定义和使用,已经有诸多的人讲解过,并且讲解细致入微,尤其是张子阳的那一篇.我就不 ...
- 解决 EF whereT(func) 查询的一个性能问题
前两年帮朋友 做了个网吧管理软件,采用动软的三层架构 sql语句生成的.最近因功能变更 要改动,而我这段正在做asp.net mvc +ef+autofac的一个电商网站.索性 就把原来的底层全重新了 ...
- Delegate,Action,Func,匿名方法,匿名委托,事件
一.委托Delegate 一般的方法(Method)中,我们的参数总是string,int,DateTime...这些基本的数据类型(或者没有参数),比如 [c-sharp] view plainco ...
- C#之Action和Func的用法
以前我都是通过定义一个delegate来写委托的,但是最近看一些外国人写的源码都是用action和func方式来写,当时感觉对这很陌生所以看起源码也觉得陌生,所以我就花费时间来学习下这两种方式,然后发 ...
- 七天学习计划_c#_[2][3][4][5]委托、事件、委托与事件的区别、泛型委托、Func\Action\predicate
由于委托之前的博客已经详细写了,这里就简单的过一遍,复习一下: 了解委托 基于委托开发事件驱动程序变得非常简单. 使用委托可以大大简化多线程编程难度. 理解委托 委托也可以看做成一种数据类型,可以定义 ...
- Func与Action
平时我们如果要用到委托一般都是先声明一个委托类型,比如: private delegate string Say(); string说明适用于这个委托的方法的返回类型是string类型,委托名Say后 ...
最新文章
- 安卓从sd引导linux,从android中的adb shell手动挂载SD卡
- nokia 基亚 wp 开发中心
- 牛客网7-教417题解
- 【剑指offer】反转链表
- svn cleanup failed–previous operation has not finished; run cleanup if it was interrupted
- Java中bytebuffer和string的转换记录
- 常用的JS小功能整理
- easyui中combotree只能选子选项,父级不被选中
- hashcat 基本使用
- 99%的程序员都在用Lombok,原理竟然这么简单?我也手撸了一个!
- 2017.8.8 loli测试
- leetcode题库1314-- 矩阵区域和
- java biz层创建代码_BIZ层调试方法
- java人脸识别开源算法_开源-人脸识别认证-java封装
- css3仿手机版淘宝商品并列显示
- 服务器安装cos系统,COS(国产操作系统)安装教程
- APK改之理使用技巧
- 在龙芯电脑制作 debian 系统(MIPS)
- 戴尔服务器安装ESXI
- 自定义view从0到1
热门文章
- mikrotikROS系统的几种安装方法
- linux进程通讯-纯文本文件
- 多种方法解决Exchange 2010 EMC批量启用邮箱之后出..
- Windows 2003下×××服务器架设攻略
- 使用Treeview模拟操作系统的文件系统
- 奇迹暖暖服务器不稳定,闪耀暖暖用土豆当服务器?开服仅半小时就崩溃,无数玩家疯狂吐槽...
- windows编译libevent时报告“缺少print_winsock_errors.obj”的解决
- java爬虫-简单爬取网页图片
- android 游戏 重力
- 如何使用Windows搜索在任何文件中搜索文本