用BenchmarkDotNet看Property

Posted dotNET跨平台

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用BenchmarkDotNet看Property相关的知识,希望对你有一定的参考价值。

属性——Property,由get,set访问器组成,这是C#使用度比较高的类成员。今天分几组对比测试,来看一下使用Property的性能。

被测试对象:

public class MyClass
{
    private string _myProperty1 = DateTime.Now.ToString();
    public string MyProperty1 { get { return _myProperty1; } }


    public string MyProperty2 { get { return DateTime.Now.ToString(); } }


    public string MyMethod()
    {
        return DateTime.Now.ToString();
    }
}

调用测试方法统一如下:

BenchmarkRunner.Run<TestProperty>();

第一组:构造实例化对象和方法内实例化对象,调用属性差多少

[MemoryDiagnoser]
public class TestProperty
{
    private readonly MyClass _myClass;
    public TestProperty()
    {
        _myClass = new MyClass();
    }
    [Benchmark]
    public string PropertyA()
    {
        return _myClass.MyProperty1;
    }
    [Benchmark]
    public string PropertyAExt()
    {
        var myClass = new MyClass();
        return myClass.MyProperty1;
    }
}

结果:差别很大,因为毕竟有一个new的过程,需要开销,同时也能理解,提交初始尽量初始化,多次调用时就开销变少了。

第二组:比较用字段属性和无字段属性的差别

[MemoryDiagnoser]
public class TestProperty
{
    private readonly MyClass _myClass;
    public TestProperty()
    {
        _myClass = new MyClass();
    }
    [Benchmark]
    public string PropertyA()
    {
        return _myClass.MyProperty1;
    }
    [Benchmark]
    public string PropertyAExt()
    {
        var myClass = new MyClass();
        return myClass.MyProperty1;
    }
    [Benchmark]
    public string PropertyB()
    {
        return _myClass.MyProperty2;
    }    
    [Benchmark]
    public string PropertyBExt()
    {
        var myClass = new MyClass();
        return myClass.MyProperty2;
    }
}

结果:这组结果显示,有字段的属性更快,因为当类实体化时,字段的值已经初始化完成,所以PropertyA要好于PropertyB,关于PropertyBExt,初始化字段+实例化对象,都占了300ns。


第三组:用反射访问属性与正常访问属性对比

[MemoryDiagnoser]
public class TestProperty
{
    private readonly MyClass _myClass;
    private readonly PropertyInfo _proinfo;
    public TestProperty()
    {
        _myClass = new MyClass();
        _proinfo = _myClass.GetType().GetProperty("MyProperty");
   }


    [Benchmark]
    public string PropertyA()
    {
        return _myClass.MyProperty1;
    }
    [Benchmark]
    public string PropertyAExt()
    {
        var myClass = new MyClass();
        return myClass.MyProperty1;
    }
    [Benchmark]
    public string PropertyB()
    {
        return _proinfo.GetValue(_myClass).ToString();


    }
    [Benchmark]
    public string PropertyBExt()
    {
        var myClass = new MyClass();
        var proinfo = myClass.GetType().GetProperty("MyProperty");
        return proinfo.GetValue(myClass).ToString();
    }
}

结果:反射调用肯定要比正常调用差一些,无可厚非,仅供参考

第四组:重点看一下代理的性能比较

[MemoryDiagnoser]
public class TestProperty
{
    private readonly MyClass _myClass;
    private readonly PropertyInfo _proinfo;
    private readonly Func<MyClass, string> _delegate;


    public TestProperty()
    {
        _myClass = new MyClass();
        _proinfo = _myClass.GetType().GetProperty("MyProperty1");
        _delegate = (Func<MyClass, string>)Delegate.CreateDelegate(typeof(Func<MyClass, string>), _proinfo.GetGetMethod(true)!);
    }


    [Benchmark]
    public string PropertyA()
    {
        return _myClass.MyProperty1;
    }
    [Benchmark]
    public string PropertyAExt()
    {
        var myClass = new MyClass();
        return myClass.MyProperty1;
    }
    [Benchmark]
    public string PropertyB()
    {
        return _proinfo.GetValue(_myClass).ToString();
    }
    [Benchmark]
    public string PropertyBExt()
    {
        var myClass = new MyClass();
        var proinfo = myClass.GetType().GetProperty("MyProperty1");
        return proinfo.GetValue(myClass).ToString();
    }
    [Benchmark]
    public string PropertyC()
    {
        var value = _delegate(_myClass);
        return value;
    }
    [Benchmark]
    public string PropertyCExt()
    {
        var myClass = new MyClass();
        var proinfo = myClass.GetType().GetProperty("MyProperty1");
        var dele = (Func<MyClass, string>)Delegate.CreateDelegate(typeof(Func<MyClass, string>), proinfo.GetGetMethod(true)!);
        return dele(_myClass);
    }
}

结果:PropertyC代理方式与PropertyA接近,看来在其他场景中可以参考使用。但PropertyCExt要开销的多的多,看来这是提前在实例化时做了工作,所以在代理调用时才开销变少。

以上是关于用BenchmarkDotNet看Property的主要内容,如果未能解决你的问题,请参考以下文章

在 XUnit 中运行 BenchmarkDotNet

.NET Core中的性能测试工具BenchmarkDotnet

BenchmarkDotNet性能测试

使用 BenchmarkDotNet 比较指定容量的 List 的性能

C#性能测试BenchmarkDotnet

深入浅出-样式属性布局