加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – 为什么不同方式通过代表的性能有如此大的差异?

发布时间:2020-12-15 06:49:13 所属栏目:百科 来源:网络整理
导读:我试图比较三种不同的方法,通过lambda,委托和直接引用将代理传递给C#中的函数.真正让我感到意外的是直接参考方法(即ComputeStringFunctionViaFunc(object [i] .ToString))比其他方法慢六倍.有人知道这是为什么吗? 完整的代码如下: using System;using Syst
我试图比较三种不同的方法,通过lambda,委托和直接引用将代理传递给C#中的函数.真正让我感到意外的是直接参考方法(即ComputeStringFunctionViaFunc(object [i] .ToString))比其他方法慢六倍.有人知道这是为什么吗?

完整的代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.CompilerServices;

namespace FunctionInvocationTest
{
    class Program
    {
        static void Main(string[] args)
        {
            object[] objectArray = new object[10000000];
            for (int i = 0; i < objectArray.Length; ++i) { objectArray[i] = new object(); }

            ComputeStringFunction(objectArray[0]);
            ComputeStringFunctionViaFunc(objectArray[0].ToString);
            ComputeStringFunctionViaFunc(delegate() { return objectArray[0].ToString(); });
            ComputeStringFunctionViaFunc(() => objectArray[0].ToString());

            System.Diagnostics.Stopwatch s = new System.Diagnostics.Stopwatch();
            s.Start();
            for (int i = 0; i < objectArray.Length; ++i)
            {
                ComputeStringFunction(objectArray[i]);
            }
            s.Stop();
            Console.WriteLine(s.Elapsed.TotalMilliseconds);

            s.Reset();
            s.Start();
            for (int i = 0; i < objectArray.Length; ++i)
            {
                ComputeStringFunctionViaFunc(delegate() { return objectArray[i].ToString(); });
            }
            s.Stop();
            Console.WriteLine(s.Elapsed.TotalMilliseconds);

            s.Reset();
            s.Start();
            for (int i = 0; i < objectArray.Length; ++i)
            {
                ComputeStringFunctionViaFunc(objectArray[i].ToString);
            }
            s.Stop();
            Console.WriteLine(s.Elapsed.TotalMilliseconds);

            s.Reset();
            s.Start();
            for (int i = 0; i < objectArray.Length; ++i)
            {
                ComputeStringFunctionViaFunc(() => objectArray[i].ToString());
            }
            s.Stop();
            Console.WriteLine(s.Elapsed.TotalMilliseconds);

            Console.ReadLine();
        }

        [MethodImpl(MethodImplOptions.NoInlining)]
        public static void ComputeStringFunction(object stringFunction)
        {
        }

        public static void ComputeStringFunctionViaFunc(Func<string> stringFunction)
        {
        }
    }
}

解决方法

固定代码以实际调用ToString()/ stringFunction(),并使用Mono 2.10.9进行测量:

ComputeStringFunctionViaFunc(objectArray [I]的ToString);因为object.ToString是虚拟的,所以很慢.检查每个对象,以防它覆盖ToString,并且应该调用重写的ToString.您的其他代表被创建来引用一个非虚函数(fast),它直接调用一个虚函数(也是fast).当修改生成的IL以更改时,可以看到这是事实的事实

ldelem.ref
dup 
ldvirtftn instance string object::ToString()

ldelem.ref
ldftn instance string object::ToString()

它总是引用object.ToString,永远??不要重写函数.然后,这三种方法都需要大致相同的时间.

更新:一个额外的方法,直接绑定到objectArray [i],但仍然虚拟地调用ToString:

for (int i = 0; i < objectArray.Length; ++i)
{
    ComputeStringFunctionViaFunc(objectArray[i].ToStringHelper);
}

static class Extensions
{
    public static string ToStringHelper(this object obj)
    {
        return obj.ToString();
    }
}

也给出与其他非虚拟代表大致相同的时间.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读