跨程序集,类与结构体究竟谁快

作者: 仪器仪表  发布:2019-11-26

前边的叁遍测量试验都以在同一个项目内的,既处于同三个主次集。那么,跨程序集调用会怎样呢?

上次自个儿对C#类与结构体做了二次速度评测(卡塔 尔(阿拉伯语:قطر‎。经过意气风发段时间考虑,发掘还能够更进一竿搜求——

原先自身直接有个疑忌——在C#中,毕竟是类(class卡塔 尔(英语:State of Qatar)比非常快,依旧结构体(struct卡塔尔不慢?
眼看并未有索求。

因为为了确定保障可维护性,我们会把一些常用操作封装到类库中去。然后实际项目支出时,援引该类库,使得应用方案中存在八个等级次序。编写翻译实现后,将会是八个根本的exe和若干个dll文件,主exe程序聚集的代码会调用dll程序集,既产生了跨程序集调用。

首先、栈变量。上次的“硬编码”,是访谈类中的静态变量的。若改为访谈函数中的栈变量,质量会不会有所升高?
其次、栈分配(stackalloc卡塔 尔(阿拉伯语:قطر‎。既然要测量检验栈变量,我们还足以顺便测量试验一下在栈上分配的内存块的拜访质量。
其三、60位整数。由于叁14位系统的成功,我们曾经习认为常了运用三十一个人整数(int卡塔 尔(英语:State of Qatar)。未来61位系统稳步普遍,大家得为此做好盘算。对于指针操作时平日要用到的偏移量增减运算来讲,是选取叁十二人整数,照旧使用64个人整数,或写两套代码?那需求测量检验后工夫说了算。
第四、密闭类(sealed卡塔尔国。听他们讲密闭类能增长品质,大家得以测量检验一下。有三种测验方法,一是为原来的派生类扩张sealed关键字,二是专门其余写三个密闭类。笔者决定同时利用那三种办法,分别测验其属性。

新近自己遇上贰个难点,供给将生龙活虎部分运算大的指针操作代码给封装一下。原先为了品质,那几个代码是以硬编码的款型混杂在算法逻辑之中,不但影响了算法逻辑的可读性,其自己的指针操作代码枯燥、难懂、易写错,不易维护。所以本身期望将其包装一下,简化代码编写、升高可维护性,但还要要硬着头皮地保管品质。
由于这些指针操作代码很利索,简单的卷入不可能一举成功难点,还索要动用接口(interface卡塔尔国以达成部分动态调用成效。
为了简化代码,还计划达成部分泛型方法。
道理当然是这样的还想因叁十三人指针、六18位指针的比不上而构造泛型类,缺憾开采C#不扶植将int/long作为泛型类型限制,只可以作罢。将统筹改为——分别为32人指针、60位指针编写差别的类,它们贯彻同八个接口。

解析跨程序集调用的特性,有助优化类库架构的宏图。

生机勃勃、测量试验代码

  测验代码如下——

using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;

namespace TryPointerCall
{
    /// <summary>
    /// 指针操作接口
    /// </summary>
    public interface IPointerCall
    {
        /// <summary>
        /// 指针操作
        /// </summary>
        /// <param name="p">源指针</param>
        /// <returns>修改后指针</returns>
        unsafe byte* Ptr(byte* p);
    }

#region 非泛型
    /// <summary>
    /// [非泛型] 指针操作基类
    /// </summary>
    public abstract class PointerCall : IPointerCall
    {
        public abstract unsafe byte* Ptr(byte* p);
    }

    /// <summary>
    /// [非泛型] 指针操作派生类: 指针+偏移
    /// </summary>
    public sealed class PointerCallAdd : PointerCall
    {
        /// <summary>
        /// 偏移值
        /// </summary>
        public int Offset = 0;

        public override unsafe byte* Ptr(byte* p)
        {
            return unchecked(p + Offset);
        }
    }

    /// <summary>
    /// [非泛型] 指针操作密封类: 指针+偏移
    /// </summary>
    public sealed class SldPointerCallAdd : IPointerCall
    {
        /// <summary>
        /// 偏移值
        /// </summary>
        public int Offset = 0;

        public unsafe byte* Ptr(byte* p)
        {
            return unchecked(p + Offset);
        }
    }

    /// <summary>
    /// [非泛型] 指针操作结构体: 指针+偏移
    /// </summary>
    public struct SPointerCallAdd : IPointerCall
    {
        /// <summary>
        /// 偏移值
        /// </summary>
        public int Offset;

        public unsafe byte* Ptr(byte* p)
        {
            return unchecked(p + Offset);
        }
    }

#endregion

#region 泛型
    // !!! C#不支持将整数类型作为泛型约束 !!!
    //public abstract class GenPointerCall<T> : IPointerCall where T: int, long
    //{
    //    public abstract unsafe byte* Ptr(byte* p);

    //    void d()
    //    {
    //    }
    //}

#endregion

#region 全部测试
    /// <summary>
    /// 指针操作的一些常用函数
    /// </summary>
    public static class PointerCallTool
    {
#if DEBUG
        private const int CountLoop = 10000000; // 循环次数
#else
        private const int CountLoop = 200000000;    // 循环次数
#endif

        /// <summary>
        /// 调用指针操作
        /// </summary>
        /// <typeparam name="T">具有IPointerCall接口的类型。</typeparam>
        /// <param name="ptrcall">调用者</param>
        /// <param name="p">源指针</param>
        /// <returns>修改后指针</returns>
        public static unsafe byte* CallPtr<T>(T ptrcall, byte* p) where T : IPointerCall
        {
            return ptrcall.Ptr(p);
        }
        public static unsafe byte* CallClassPtr<T>(T ptrcall, byte* p) where T : PointerCall
        {
            return ptrcall.Ptr(p);
        }
        public static unsafe byte* CallRefPtr<T>(ref T ptrcall, byte* p) where T : IPointerCall
        {
            return ptrcall.Ptr(p);
        }

        // C#不允许将特定的结构体作为泛型约束。所以对于结构体只能采用上面那个方法,通过IPointerCall接口进行约束,可能会造成性能下降。
        //public static unsafe byte* SCallPtr<T>(T ptrcall, byte* p) where T : SPointerCallAdd
        //{
        //    return ptrcall.Ptr(p);
        //}

        private static int TryIt_Static_Offset;
        private static unsafe byte* TryIt_Static_Ptr(byte* p)
        {
            return unchecked(p + TryIt_Static_Offset);
        }
        /// <summary>
        /// 执行测试 - 静态调用
        /// </summary>
        /// <param name="sOut">文本输出</param>
        private static unsafe void TryIt_Static(StringBuilder sOut, int CountLoop)
        {
            TryIt_Static_Offset = 1;

            // == 性能测试 ==
            byte* p = null;
            Stopwatch sw = new Stopwatch();
            int i;
            unchecked
            {
                #region 测试
                // 硬编码.栈变量
                int iOffset = 1;
                sw.Reset();
                sw.Start();
                for (i = 0; i < CountLoop; ++i)
                {
                    p = p + iOffset;
                }
                sw.Stop();
                sOut.AppendLine(string.Format("硬编码.栈变量:t{0}", sw.ElapsedMilliseconds));

                // 硬编码.栈分配
                int* pOffset = stackalloc int[1];
                pOffset[0] = 1;
                sw.Reset();
                sw.Start();
                for (i = 0; i < CountLoop; ++i)
                {
                    p = p + pOffset[0];
                }
                sw.Stop();
                sOut.AppendLine(string.Format("硬编码.栈分配:t{0}", sw.ElapsedMilliseconds));

                // 硬编码.静态
                sw.Reset();
                sw.Start();
                for (i = 0; i < CountLoop; ++i)
                {
                    p = p + TryIt_Static_Offset;
                }
                sw.Stop();
                sOut.AppendLine(string.Format("硬编码.静态:t{0}", sw.ElapsedMilliseconds));

                // 静态调用
                sw.Reset();
                sw.Start();
                for (i = 0; i < CountLoop; ++i)
                {
                    p = TryIt_Static_Ptr(p);
                }
                sw.Stop();
                sOut.AppendLine(string.Format("静态调用:t{0}", sw.ElapsedMilliseconds));

                #endregion // 测试
            }
        }

        private static long TryIt_Static64_Offset;
        private static unsafe byte* TryIt_Static64_Ptr(byte* p)
        {
            return unchecked(p + TryIt_Static64_Offset);
        }
        /// <summary>
        /// 执行测试 - 静态调用
        /// </summary>
        /// <param name="sOut">文本输出</param>
        private static unsafe void TryIt_Static64(StringBuilder sOut, int CountLoop)
        {
            TryIt_Static64_Offset = 1;

            // == 性能测试 ==
            byte* p = null;
            Stopwatch sw = new Stopwatch();
            int i;
            unchecked
            {
                #region 测试
                // 硬编码.栈变量
                long iOffset = 1;
                sw.Reset();
                sw.Start();
                for (i = 0; i < CountLoop; ++i)
                {
                    p = p + iOffset;
                }
                sw.Stop();
                sOut.AppendLine(string.Format("64硬编码.栈变量:t{0}", sw.ElapsedMilliseconds));

                // 硬编码.栈分配
                long* pOffset = stackalloc long[1];
                pOffset[0] = 1;
                sw.Reset();
                sw.Start();
                for (i = 0; i < CountLoop; ++i)
                {
                    p = p + pOffset[0];
                }
                sw.Stop();
                sOut.AppendLine(string.Format("64硬编码.栈分配:t{0}", sw.ElapsedMilliseconds));

                // 硬编码.静态
                sw.Reset();
                sw.Start();
                for (i = 0; i < CountLoop; ++i)
                {
                    p = p + TryIt_Static64_Offset;
                }
                sw.Stop();
                sOut.AppendLine(string.Format("64硬编码.静态:t{0}", sw.ElapsedMilliseconds));

                // 静态调用
                sw.Reset();
                sw.Start();
                for (i = 0; i < CountLoop; ++i)
                {
                    p = TryIt_Static64_Ptr(p);
                }
                sw.Stop();
                sOut.AppendLine(string.Format("64静态调用:t{0}", sw.ElapsedMilliseconds));

                #endregion // 测试
            }
        }

        /// <summary>
        /// 执行测试 - 非泛型
        /// </summary>
        /// <param name="sOut">文本输出</param>
        private static unsafe void TryIt_NoGen(StringBuilder sOut, int CountLoop)
        {
            // 创建
            PointerCallAdd pca = new PointerCallAdd();
            SldPointerCallAdd dpca = new SldPointerCallAdd();
            SPointerCallAdd spca;
            pca.Offset = 1;
            spca.Offset = 1;

            // 转型
            PointerCall pca_base = pca;
            IPointerCall pca_itf = pca;
            IPointerCall dpca_itf = dpca;
            IPointerCall spca_itf = spca;

            // == 性能测试 ==
            byte* p = null;
            Stopwatch sw = new Stopwatch();
            int i;
            unchecked
            {
                #region 调用
                #region 直接调用
                // 调用派生类
                sw.Reset();
                sw.Start();
                for (i = 0; i < CountLoop; ++i)
                {
                    p = pca.Ptr(p);
                }
                sw.Stop();
                sOut.AppendLine(string.Format("调用派生类:t{0}", sw.ElapsedMilliseconds));

                // 调用密封类
                sw.Reset();
                sw.Start();
                for (i = 0; i < CountLoop; ++i)
                {
                    p = dpca.Ptr(p);
                }
                sw.Stop();
                sOut.AppendLine(string.Format("调用密封类:t{0}", sw.ElapsedMilliseconds));

                // 调用结构体
                sw.Reset();
                sw.Start();
                for (i = 0; i < CountLoop; ++i)
                {
                    p = spca.Ptr(p);
                }
                sw.Stop();
                sOut.AppendLine(string.Format("调用结构体:t{0}", sw.ElapsedMilliseconds));

                #endregion  // 直接调用

                #region 间接调用
                // 调用基类
                sw.Reset();
                sw.Start();
                for (i = 0; i < CountLoop; ++i)
                {
                    p = pca_base.Ptr(p);
                }
                sw.Stop();
                sOut.AppendLine(string.Format("调用基类:t{0}", sw.ElapsedMilliseconds));

                // 调用派生类的接口
                sw.Reset();
                sw.Start();
                for (i = 0; i < CountLoop; ++i)
                {
                    p = pca_itf.Ptr(p);
                }
                sw.Stop();
                sOut.AppendLine(string.Format("调用派生类的接口:t{0}", sw.ElapsedMilliseconds));

                // 调用密封类的接口
                sw.Reset();
                sw.Start();
                for (i = 0; i < CountLoop; ++i)
                {
                    p = dpca_itf.Ptr(p);
                }
                sw.Stop();
                sOut.AppendLine(string.Format("调用密封类的接口:t{0}", sw.ElapsedMilliseconds));

                // 调用结构体的接口
                sw.Reset();
                sw.Start();
                for (i = 0; i < CountLoop; ++i)
                {
                    p = spca_itf.Ptr(p);
                }
                sw.Stop();
                sOut.AppendLine(string.Format("调用结构体的接口:t{0}", sw.ElapsedMilliseconds));

                #endregion  // 间接调用

                #endregion  // 调用

                #region 泛型调用

                #region 泛型基类约束
                // 基类泛型调用派生类
                sw.Reset();
                sw.Start();
                for (i = 0; i < CountLoop; ++i)
                {
                    p = CallClassPtr(pca, p);
                }
                sw.Stop();
                sOut.AppendLine(string.Format("基类泛型调用派生类:t{0}", sw.ElapsedMilliseconds));

                // 基类泛型调用基类
                sw.Reset();
                sw.Start();
                for (i = 0; i < CountLoop; ++i)
                {
                    p = CallClassPtr(pca_base, p);
                }
                sw.Stop();
                sOut.AppendLine(string.Format("基类泛型调用基类:t{0}", sw.ElapsedMilliseconds));

                #endregion // 泛型基类约束

                #region 泛型接口约束 - 直接调用
                // 接口泛型调用派生类
                sw.Reset();
                sw.Start();
                for (i = 0; i < CountLoop; ++i)
                {
                    p = CallPtr(pca, p);
                }
                sw.Stop();
                sOut.AppendLine(string.Format("接口泛型调用派生类:t{0}", sw.ElapsedMilliseconds));

                // 接口泛型调用密封类
                sw.Reset();
                sw.Start();
                for (i = 0; i < CountLoop; ++i)
                {
                    p = CallPtr(dpca, p);
                }
                sw.Stop();
                sOut.AppendLine(string.Format("接口泛型调用密封类:t{0}", sw.ElapsedMilliseconds));

                // 接口泛型调用结构体
                sw.Reset();
                sw.Start();
                for (i = 0; i < CountLoop; ++i)
                {
                    p = CallPtr(spca, p);
                }
                sw.Stop();
                sOut.AppendLine(string.Format("接口泛型调用结构体:t{0}", sw.ElapsedMilliseconds));

                // 接口泛型调用结构体引用
                sw.Reset();
                sw.Start();
                for (i = 0; i < CountLoop; ++i)
                {
                    p = CallRefPtr(ref spca, p);
                }
                sw.Stop();
                sOut.AppendLine(string.Format("接口泛型调用结构体引用:t{0}", sw.ElapsedMilliseconds));

                #endregion  // 直接调用

                #region 间接调用
                // 接口泛型调用基类
                sw.Reset();
                sw.Start();
                for (i = 0; i < CountLoop; ++i)
                {
                    p = CallPtr(pca_base, p);
                }
                sw.Stop();
                sOut.AppendLine(string.Format("接口泛型调用基类:t{0}", sw.ElapsedMilliseconds));

                // 接口泛型调用派生类的接口
                sw.Reset();
                sw.Start();
                for (i = 0; i < CountLoop; ++i)
                {
                    p = CallPtr(pca_itf, p);
                }
                sw.Stop();
                sOut.AppendLine(string.Format("接口泛型调用派生类的接口:t{0}", sw.ElapsedMilliseconds));

                // 接口泛型调用密封类的接口
                sw.Reset();
                sw.Start();
                for (i = 0; i < CountLoop; ++i)
                {
                    p = CallPtr(dpca_itf, p);
                }
                sw.Stop();
                sOut.AppendLine(string.Format("接口泛型调用密封类的接口:t{0}", sw.ElapsedMilliseconds));

                // 接口泛型调用结构体的接口
                sw.Reset();
                sw.Start();
                for (i = 0; i < CountLoop; ++i)
                {
                    p = CallPtr(spca_itf, p);
                }
                sw.Stop();
                sOut.AppendLine(string.Format("接口泛型调用结构体的接口:t{0}", sw.ElapsedMilliseconds));

                #endregion  // 间接调用

                #endregion  // 泛型调用

            }
        }

        /// <summary>
        /// 执行测试 - 泛型
        /// </summary>
        /// <param name="sOut">文本输出</param>
        private static unsafe void TryIt_Gen(StringBuilder sOut, int CountLoop)
        {
            // !!! C#不支持将整数类型作为泛型约束 !!!
        }

        /// <summary>
        /// 执行测试
        /// </summary>
        public static string TryIt()
        {
            StringBuilder sOut = new StringBuilder();
            sOut.AppendLine("== PointerCallTool.TryIt() ==");
            TryIt_Static(sOut, CountLoop);
            TryIt_Static64(sOut, CountLoop);
            TryIt_NoGen(sOut, CountLoop);
            TryIt_Gen(sOut, CountLoop);
            sOut.AppendLine();
            return sOut.ToString();
        }

        /// <summary>
        /// 执行测试 - static
        /// </summary>
        public static string TryItStatic()
        {
            StringBuilder sOut = new StringBuilder();
            int cnt = CountLoop * 10;
            sOut.AppendLine("== PointerCallTool.TryItStatic() ==");
            TryIt_Static(sOut, cnt);
            TryIt_Static64(sOut, cnt);
            sOut.AppendLine();
            return sOut.ToString();
        }
    }
#endregion

}

 

在C#中,有两类包装手艺——
1.基于类(class卡塔 尔(阿拉伯语:قطر‎的卷入。在基类中定义好操作方法,然后在派生类中贯彻际操作作方法。
2.基于结构体(struct卡塔 尔(英语:State of Qatar)的卷入。在接口中定义好操作方法,然后在结构体中落到实处该接口的操作方法。
自己分别接收这两类包装技艺编写测量试验代码,然后做品质测量试验。

生机勃勃、测量试验方法

二、测量检验境遇

  编译器——
VS2005:Visual Studio 2005 SP1。
VS2010:Visual Studio 2010 SP1。
行使上述编写翻译器编写翻译为Release版程序,最大速度优化。

  机器A——
HP CQ42-153TX
处理器:Intel Core i5-430M(2.26GHz, Turbo 2.53GHz, 3MB L3)
内部存款和储蓄器体量:2GB (DD昂科雷3-1066)

  机器B——
DELL Latitude E6320 
处理器:Intel i3-2310M(2.1GHz, 3MB L3)
内部存款和储蓄器体量:4GB (DD奥德赛3-1333,双大路)

  测验碰着——
A_2005:机器A,VS2005,Window 7 32位。
A_2010:机器A,VS2010,Window 7 32位。
B_2005:机器B,VS2005,Window XP SP3 32位。
B_2010:机器B,VS2010,Window XP SP3 32位。
B64_2005:机器B,VS2005,Window 7 64位(x64)。
B64_2010:机器B,VS2010,Window 7 64位(x64)。

经过每每思忖,考虑 类、结构体、接口、泛型 的整合,作者搜索了15种函数调用格局——
硬编码
静态调用
调用派生类
调用结构体
调用基类
调用派生类的接口
调用结构体的接口
基类泛型调用派生类
基类泛型调用基类
接口泛型调用派生类
接口泛型调用结构体
接口泛型调用结构体援引
接口泛型调用基类
接口泛型调用派生类的接口
接口泛型调用结构体的接口

骨子里步骤很简短——
1.重复展开VS二〇〇五。或关闭建设方案。
2.新建二个“Windows应用程序”项目。如“TryPointerCallns二零零五”。
3.增添种类,选拔上次的“TryPointerCall二零零七”。今后设计方案中就有三个类型了。
4.增选第2步时新建的品类(TryPointerCallns贰零零陆卡塔尔,增加援引,将“TryPointerCall2006”加上去。
5.调节项目性质,允许不安全的代码。
6.新建三个类(TestCall卡塔 尔(英语:State of Qatar),将测量试验代码全体Copy过来(注意只复制测量试验代码,不复制IPointerCall、PointerCall等贯彻卡塔 尔(英语:State of Qatar)。
7.更改窗口分界面,调用TestCall的测验代码。

三、硬编码与静态调用 的测验结果(栈变量、栈分配、陆拾四位整数卡塔 尔(英语:State of Qatar)

  因为硬编码与静态调用很也许会被实行函数展开优化,速度显明比别的测验项目要快。所笔者其余写了多少个测验函数(TryItStatic卡塔 尔(阿拉伯语:قطر‎,将循环次数设为原本的10倍。

  测量试验结果如下(单位:飞秒)——

模式 A_2005 A_2010 B_2005 B_2010 B64_2005 B64_2010
硬编码.栈变量: 1608 1623 957 966 960 959
硬编码.栈分配: 1612 1617 1073 957 961 960
硬编码.静态: 1609 1613 957 971 961 960
静态调用: 1608 1611 1063 958 961 963
64硬编码.栈变量: 1610 1617 967 957 959 1010
64硬编码.栈分配: 1610 1619 1034 957 960 1012
64硬编码.静态: 1609 1618 999 996 957 1010
64静态调用: 1610 1615 959 1002 957 7696

  结果深入分析——
先看三拾几个人与陆13个人的差异。发将来大多数景色,三十一个人与60位的速度是大器晚成律的。唯豆蔻梢头正是六12个人整数运算代码在“64人平台+VS二〇〇九”上运营时,速度比在30个人下还慢,尤其是静态调用慢了有些倍,硬编码代码的进程也具备下滑。真的很意外,既然运转的是雷同份程序,为啥六拾个人比32个人还慢,难道是.Net 4.0在x64平台上的即时编写翻译器的难点?不解。
栈变量、栈分配、静态变量的访问速度差相当少千篇大器晚成律,看来能够放心地任意动用。

  看来现在写指针操作代码时,只写陆拾几个人整数版就能够了。

测量试验代码为—— 

图片 1

四、密封类 的测量检验结果

  测量试验结果如下(单位:微秒卡塔尔——
模式 A_2005 A_2010 B_2005 B_2010 B64_2005B64_2010
硬编码.栈变量: 162 162 95 95 96 95
硬编码.栈分配: 161 161 95 95 95 97
硬编码.静态: 161 165 97 95 97 95
静态调用: 161 163 95 95 96 97
64硬编码.栈变量: 161161989596 100
64硬编码.栈分配: 160162959795 100
64硬编码.静态: 162 162 95 97 95 100
64静态调用: 161 161 95 95 97 770
调用派生类: 563 568 670 668 676 580
调用密闭类: 161 162 101 103 102 767
调用结构体: 163 161 116 102 191 772
调用基类: 566 573 668 660 675 577
调用派生类的接口: 727 731 767 862 862 770
调用密闭类的接口: 721 730 957 862 870 771
调用结构体的接口: 104511341318134013441253
基类泛型调用派生类: 910795127478912561287
基类泛型调用基类: 902 785 1092 676 1346 1250
接口泛型调用派生类: 1407733163486216331633
接口泛型调用密封类: 1405808173395617431638
接口泛型调用结构体: 5661606711018641250
接口泛型调用结构体援引: 48016170098769961
接口泛型调用基类: 1409728176776416311635
接口泛型调用派生类的接口: 1410727170296617301634
接口泛型调用密封类的接口: 140280817壹玖玖贰816351637
接口泛型调用结构体的接口: 161711281859149922082117

  将测量检验结果再行排版一下,特出分裂完毕格局的快慢分别——

环境 分类 基类 派生类 密封类 结构体 结构体的引用
A_2005 直接调用 566 563 161 163  
  接口调用   727 721 1045  
  基类约束泛型调用 902 910      
  接口约束泛型调用   1407 1405 566 480
  接口约束泛型调用接口 1409 1410 1402 1617  
A_2010 直接调用 573 568 162 161  
  接口调用   731 730 1134  
  基类约束泛型调用 785 795      
  接口约束泛型调用   733 808 160 161
  接口约束泛型调用接口 728 727 808 1128  
B_2005 直接调用 668 670 101 116  
  接口调用   767 957 1318  
  基类约束泛型调用 1092 1274      
  接口约束泛型调用   1634 1733 671 700
  接口约束泛型调用接口 1767 1702 1719 1859  
B_2010 直接调用 660 668 103 102  
  接口调用   862 862 1340  
  基类约束泛型调用 676 789      
  接口约束泛型调用   862 956 101 98
  接口约束泛型调用接口 764 966 958 1499  
B64_2005 直接调用 675 676 102 191  
  接口调用   862 870 1344  
  基类约束泛型调用 1346 1256      
  接口约束泛型调用   1633 1743 864 769
  接口约束泛型调用接口 1631 1730 1635 2208  
B64_2010 直接调用 577 580 767 772  
  接口调用   770 771 1253  
  基类约束泛型调用 1250 1287      
  接口约束泛型调用   1633 1638 1250 961
  接口约束泛型调用接口 1635 1634 1637 2117  

  综合来看,密闭类的性情最佳,在大超多测验项目中规范——
“直接调用”时能被内联(inline卡塔尔优化,与“硬编码”雷同快,快于派生类。
“接口调用”、“泛型调用接口”时与派生类质量相像,快于结构体的“接口调用”。
唯风华正茂正是在“泛型调用”时,落后于结构体,与派生类大致稍微慢一点。
再不怕诡异的“陆拾一人平台+VS二零一零”难点,密闭类、结构体在一向调用时,还不及派生类。

  最终总计一下只怕会被内联优化的调用类型——
三拾位平台+VS二〇〇七:调用密闭类、调用结构体。
32人平台+VS二〇〇九:调用密封类、调用结构体、接口节制泛型调用结构体。
64个人平台+VS二〇〇六:调用封闭类、调用结构体。
64位平台+VS2010:(无)。

(完)

测量试验程序exe——

源代码下载——

目录——
C#类与结构体毕竟哪个人快——各个函数调用情势速度评测:
再探C#类与结构体终究哪个人快——酌量栈变量、栈分配、63个人整数、密闭类:
三探C#类与结构体终归什么人快——MSIL(微软个中语言卡塔 尔(阿拉伯语:قطر‎解读:
四探C#类与结构体终究哪个人快——跨程序集(assembly卡塔 尔(英语:State of Qatar)调用:

using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;

namespace TryPointerCall
{
    /// <summary>
    /// 指针操作接口
    /// </summary>
    public interface IPointerCall
    {
        /// <summary>
        /// 指针操作
        /// </summary>
        /// <param name="p">源指针</param>
        /// <returns>修改后指针</returns>
        unsafe byte* Ptr(byte* p);
    }

#region 非泛型
    /// <summary>
    /// [非泛型] 指针操作基类
    /// </summary>
    public abstract class PointerCall : IPointerCall
    {
        public abstract unsafe byte* Ptr(byte* p);
    }

    /// <summary>
    /// [非泛型] 指针操作派生类: 指针+偏移
    /// </summary>
    public class PointerCallAdd : PointerCall
    {
        /// <summary>
        /// 偏移值
        /// </summary>
        public int Offset = 0;

        public override unsafe byte* Ptr(byte* p)
        {
            return unchecked(p + Offset);
        }
    }

    /// <summary>
    /// [非泛型] 指针操作结构体: 指针+偏移
    /// </summary>
    public struct SPointerCallAdd : IPointerCall
    {
        /// <summary>
        /// 偏移值
        /// </summary>
        public int Offset;

        public unsafe byte* Ptr(byte* p)
        {
            return unchecked(p + Offset);
        }
    }

#endregion

#region 泛型
    // !!! C#不支持将整数类型作为泛型约束 !!!
    //public abstract class GenPointerCall<T> : IPointerCall where T: int, long
    //{
    //    public abstract unsafe byte* Ptr(byte* p);

    //    void d()
    //    {
    //    }
    //}

#endregion

#region 全部测试
    /// <summary>
    /// 指针操作的一些常用函数
    /// </summary>
    public static class PointerCallTool
    {
        private const int CountLoop = 200000000;    // 循环次数

        /// <summary>
        /// 调用指针操作
        /// </summary>
        /// <typeparam name="T">具有IPointerCall接口的类型。</typeparam>
        /// <param name="ptrcall">调用者</param>
        /// <param name="p">源指针</param>
        /// <returns>修改后指针</returns>
        public static unsafe byte* CallPtr<T>(T ptrcall, byte* p) where T : IPointerCall
        {
            return ptrcall.Ptr(p);
        }
        public static unsafe byte* CallClassPtr<T>(T ptrcall, byte* p) where T : PointerCall
        {
            return ptrcall.Ptr(p);
        }
        public static unsafe byte* CallRefPtr<T>(ref T ptrcall, byte* p) where T : IPointerCall
        {
            return ptrcall.Ptr(p);
        }

        // C#不允许将特定的结构体作为泛型约束。所以对于结构体只能采用上面那个方法,通过IPointerCall接口进行约束,可能会造成性能下降。
        //public static unsafe byte* SCallPtr<T>(T ptrcall, byte* p) where T : SPointerCallAdd
        //{
        //    return ptrcall.Ptr(p);
        //}

        private static int TryIt_Static_Offset;
        private static unsafe byte* TryIt_Static_Ptr(byte* p)
        {
            return unchecked(p + TryIt_Static_Offset);
        }
        /// <summary>
        /// 执行测试 - 静态调用
        /// </summary>
        /// <param name="sOut">文本输出</param>
        private static unsafe void TryIt_Static(StringBuilder sOut)
        {
            TryIt_Static_Offset = 1;

            // == 性能测试 ==
            byte* p = null;
            Stopwatch sw = new Stopwatch();
            int i;
            unchecked
            {
                #region 测试
                // 硬编码
                sw.Reset();
                sw.Start();
                for (i = 0; i < CountLoop; ++i)
                {
                    p = p + TryIt_Static_Offset;
                }
                sw.Stop();
                sOut.AppendLine(string.Format("硬编码:t{0}", sw.ElapsedMilliseconds));

                // 静态调用
                sw.Reset();
                sw.Start();
                for (i = 0; i < CountLoop; ++i)
                {
                    p = TryIt_Static_Ptr(p);
                }
                sw.Stop();
                sOut.AppendLine(string.Format("静态调用:t{0}", sw.ElapsedMilliseconds));

                #endregion // 测试
            }
        }

        /// <summary>
        /// 执行测试 - 非泛型
        /// </summary>
        /// <param name="sOut">文本输出</param>
        private static unsafe void TryIt_NoGen(StringBuilder sOut)
        {
            // 创建
            PointerCallAdd pca = new PointerCallAdd();
            SPointerCallAdd spca;
            pca.Offset = 1;
            spca.Offset = 1;

            // 转型
            PointerCall pca_base = pca;
            IPointerCall pca_itf = pca;
            IPointerCall spca_itf = spca;

            // == 性能测试 ==
            byte* p = null;
            Stopwatch sw = new Stopwatch();
            int i;
            unchecked
            {
                #region 调用
                #region 直接调用
                // 调用派生类
                sw.Reset();
                sw.Start();
                for (i = 0; i < CountLoop; ++i)
                {
                    p = pca.Ptr(p);
                }
                sw.Stop();
                sOut.AppendLine(string.Format("调用派生类:t{0}", sw.ElapsedMilliseconds));

                // 调用结构体
                sw.Reset();
                sw.Start();
                for (i = 0; i < CountLoop; ++i)
                {
                    p = spca.Ptr(p);
                }
                sw.Stop();
                sOut.AppendLine(string.Format("调用结构体:t{0}", sw.ElapsedMilliseconds));

                #endregion  // 直接调用

                #region 间接调用
                // 调用基类
                sw.Reset();
                sw.Start();
                for (i = 0; i < CountLoop; ++i)
                {
                    p = pca_base.Ptr(p);
                }
                sw.Stop();
                sOut.AppendLine(string.Format("调用基类:t{0}", sw.ElapsedMilliseconds));

                // 调用派生类的接口
                sw.Reset();
                sw.Start();
                for (i = 0; i < CountLoop; ++i)
                {
                    p = pca_itf.Ptr(p);
                }
                sw.Stop();
                sOut.AppendLine(string.Format("调用派生类的接口:t{0}", sw.ElapsedMilliseconds));

                // 调用结构体的接口
                sw.Reset();
                sw.Start();
                for (i = 0; i < CountLoop; ++i)
                {
                    p = spca_itf.Ptr(p);
                }
                sw.Stop();
                sOut.AppendLine(string.Format("调用结构体的接口:t{0}", sw.ElapsedMilliseconds));

                #endregion  // 间接调用

                #endregion  // 调用

                #region 泛型调用

                #region 泛型基类约束
                // 基类泛型调用派生类
                sw.Reset();
                sw.Start();
                for (i = 0; i < CountLoop; ++i)
                {
                    p = CallClassPtr(pca, p);
                }
                sw.Stop();
                sOut.AppendLine(string.Format("基类泛型调用派生类:t{0}", sw.ElapsedMilliseconds));

                // 基类泛型调用基类
                sw.Reset();
                sw.Start();
                for (i = 0; i < CountLoop; ++i)
                {
                    p = CallClassPtr(pca_base, p);
                }
                sw.Stop();
                sOut.AppendLine(string.Format("基类泛型调用基类:t{0}", sw.ElapsedMilliseconds));

                #endregion // 泛型基类约束

                #region 泛型接口约束 - 直接调用
                // 接口泛型调用派生类
                sw.Reset();
                sw.Start();
                for (i = 0; i < CountLoop; ++i)
                {
                    p = CallPtr(pca, p);
                }
                sw.Stop();
                sOut.AppendLine(string.Format("接口泛型调用派生类:t{0}", sw.ElapsedMilliseconds));

                // 接口泛型调用结构体
                sw.Reset();
                sw.Start();
                for (i = 0; i < CountLoop; ++i)
                {
                    p = CallPtr(spca, p);
                }
                sw.Stop();
                sOut.AppendLine(string.Format("接口泛型调用结构体:t{0}", sw.ElapsedMilliseconds));

                // 接口泛型调用结构体引用
                sw.Reset();
                sw.Start();
                for (i = 0; i < CountLoop; ++i)
                {
                    p = CallRefPtr(ref spca, p);
                }
                sw.Stop();
                sOut.AppendLine(string.Format("接口泛型调用结构体引用:t{0}", sw.ElapsedMilliseconds));

                #endregion  // 直接调用

                #region 间接调用
                // 接口泛型调用基类
                sw.Reset();
                sw.Start();
                for (i = 0; i < CountLoop; ++i)
                {
                    p = CallPtr(pca_base, p);
                }
                sw.Stop();
                sOut.AppendLine(string.Format("接口泛型调用基类:t{0}", sw.ElapsedMilliseconds));

                // 接口泛型调用派生类的接口
                sw.Reset();
                sw.Start();
                for (i = 0; i < CountLoop; ++i)
                {
                    p = CallPtr(pca_itf, p);
                }
                sw.Stop();
                sOut.AppendLine(string.Format("接口泛型调用派生类的接口:t{0}", sw.ElapsedMilliseconds));

                // 接口泛型调用结构体的接口
                sw.Reset();
                sw.Start();
                for (i = 0; i < CountLoop; ++i)
                {
                    p = CallPtr(spca_itf, p);
                }
                sw.Stop();
                sOut.AppendLine(string.Format("接口泛型调用结构体的接口:t{0}", sw.ElapsedMilliseconds));

                #endregion  // 间接调用

                #endregion  // 泛型调用

            }
        }

        /// <summary>
        /// 执行测试 - 泛型
        /// </summary>
        /// <param name="sOut">文本输出</param>
        private static unsafe void TryIt_Gen(StringBuilder sOut)
        {
            // !!! C#不支持将整数类型作为泛型约束 !!!
        }

        /// <summary>
        /// 执行测试
        /// </summary>
        public static string TryIt()
        {
            StringBuilder sOut = new StringBuilder();
            sOut.AppendLine("== PointerCallTool.TryIt() ==");
            TryIt_Static(sOut);
            TryIt_NoGen(sOut);
            TryIt_Gen(sOut);
            sOut.AppendLine();
            return sOut.ToString();
        }
    }
#endregion

}

二、测验意况

编译器——
VS2005:Visual Studio 2005 SP1。
VS2010:Visual Studio 2010 SP1。
采取上述编写翻译器编写翻译为Release版程序,最大速度优化。

本文由88必发手机版发布于仪器仪表,转载请注明出处:跨程序集,类与结构体究竟谁快

关键词: