当前位置:  开发笔记 > 编程语言 > 正文

Object.GetType()的性能

如何解决《Object.GetType()的性能》经验,为你挑选了3个好方法。

我们的应用程序中有很多日志记录调用.我们的记录器采用System.Type参数,因此它可以显示创建调用的组件.有时候,当我们受到打扰时,我们会做以下事情:

class Foo
{
  private static readonly Type myType = typeof(Foo);

  void SomeMethod()
  {
     Logger.Log(myType, "SomeMethod started...");
  }
 }

因为这只需要获取Type对象一次.但是,我们没有任何实际指标.任何人都知道这节省了多少调用this.GetType()每次我们登录?

(我意识到我可以自己完成指标并没有什么大问题,但是嘿,什么是StackOverflow?)



1> Jon Skeet..:

我强烈怀疑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;
    }
}



2> bruno conde..:

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");

所以,我预计你的实现不会有太大的好处.


是什么让你觉得它每次都在创造一个新的对象?事实上,表明不是这样的事情是微不足道的.打印object.ReferenceEquals(x.GetType(),x.GetType()).
:)我甚至在你写这篇评论并纠正我的答案之前就已经这样做了.谢谢.

3> JaredPar..:

我怀疑你会在这个问题上得到满意的答案.原因是性能,特别是这种类型的场景,是高度特定于应用程序的.

有人可能会用一个快速的秒表回复一个例子,其原始毫秒数会更快.但坦率地说,这对您的申请没有任何意义.为什么?它在很大程度上取决于特定场景的使用模式.例如 ...

    你有几种类型?

    你的方法有多大?

    你是为每种方法做到这一点,还是只为大方法做?

这些只是一些会大大改变直线时间基准相关性的问题.


+1。再加上一个事实,即微基准测试可以避免代码膨胀(多余的变量)而不会造成高速缓存未命中,而在实际应用程序中,可能会创建值缓存,gc压力,高速缓存未命中,分页...微基准无关紧要。分析是一种方法。
推荐阅读
乐韵答题
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有