我们的应用程序中有很多日志记录调用.我们的记录器采用System.Type参数,因此它可以显示创建调用的组件.有时候,当我们受到打扰时,我们会做以下事情:
class Foo { private static readonly Type myType = typeof(Foo); void SomeMethod() { Logger.Log(myType, "SomeMethod started..."); } }
因为这只需要获取Type对象一次.但是,我们没有任何实际指标.任何人都知道这节省了多少调用this.GetType()每次我们登录?
(我意识到我可以自己完成指标并没有什么大问题,但是嘿,什么是StackOverflow?)
我强烈怀疑GetType()将比任何实际日志记录花费更少的时间.当然,你对Logger.Log的调用可能不会做任何实际的IO ......我仍然怀疑差异是无关紧要的.
编辑:基准代码位于底部.结果:
typeof(Test): 2756ms TestType (field): 1175ms test.GetType(): 3734ms
这种方法称之为1 亿次 - 优化会在几秒钟内完成.我怀疑真正的日志记录方法还有很多工作要做,并且调用1亿次会占用总时间超过4秒,即使它没有写出任何东西.(当然,我可能错了 - 你必须自己尝试一下.)
换句话说,正常情况下,我会使用最可读的代码,而不是微优化.
using System; using System.Diagnostics; using System.Runtime.CompilerServices; class Test { const int Iterations = 100000000; private static readonly Type TestType = typeof(Test); static void Main() { int total = 0; // Make sure it's JIT-compiled Log(typeof(Test)); Stopwatch sw = Stopwatch.StartNew(); for (int i = 0; i < Iterations; i++) { total += Log(typeof(Test)); } sw.Stop(); Console.WriteLine("typeof(Test): {0}ms", sw.ElapsedMilliseconds); sw = Stopwatch.StartNew(); for (int i = 0; i < Iterations; i++) { total += Log(TestType); } sw.Stop(); Console.WriteLine("TestType (field): {0}ms", sw.ElapsedMilliseconds); Test test = new Test(); sw = Stopwatch.StartNew(); for (int i = 0; i < Iterations; i++) { total += Log(test.GetType()); } sw.Stop(); Console.WriteLine("test.GetType(): {0}ms", sw.ElapsedMilliseconds); } // I suspect your real Log method won't be inlined, // so let's mimic that here [MethodImpl(MethodImplOptions.NoInlining)] static int Log(Type type) { return 1; } }
该GetType()
功能标有特殊属性[MethodImpl(MethodImplOptions.InternalCall)]
.这意味着它的方法体不包含IL,而是一个挂钩到.NET CLR内部的钩子.在这种情况下,它查看对象元数据的二进制结构并构造其System.Type
周围的对象.
编辑:我猜我错了什么......
我说:"因为GetType()
需要构建一个新的对象"但似乎这是不正确的.不知何故,CLR缓存Type
并始终返回相同的对象,因此不需要构建新的Type对象.
我基于以下测试:
Object o1 = new Object(); Type t1 = o1.GetType(); Type t2 = o1.GetType(); if (object.ReferenceEquals(t1,t2)) Console.WriteLine("same reference");
所以,我预计你的实现不会有太大的好处.
我怀疑你会在这个问题上得到满意的答案.原因是性能,特别是这种类型的场景,是高度特定于应用程序的.
有人可能会用一个快速的秒表回复一个例子,其原始毫秒数会更快.但坦率地说,这对您的申请没有任何意义.为什么?它在很大程度上取决于特定场景的使用模式.例如 ...
你有几种类型?
你的方法有多大?
你是为每种方法做到这一点,还是只为大方法做?
这些只是一些会大大改变直线时间基准相关性的问题.