zyl910

优化技巧、硬件体系、图像处理、图形学、游戏编程、国际化与文本信息处理。

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  215 随笔 :: 0 文章 :: 145 评论 :: 111万 阅读
< 2025年2月 >
26 27 28 29 30 31 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 1
2 3 4 5 6 7 8

上次我对C#类与结构体做了一次速度评测(http://blog.csdn.net/zyl910/article/details/6788417)。经过一段时间思索,发现还可以进一步探讨——

第一、栈变量。上次的“硬编码”,是访问类中的静态变量的。若改为访问函数中的栈变量,性能会不会有所提高?
第二、栈分配(stackalloc)。既然要测试栈变量,我们还可以顺便测试一下在栈上分配的内存块的访问性能。
第三、64位整数。由于32位系统的成功,我们已经习惯了使用32位整数(int)。现在64位系统逐渐普及,我们得为此做好准备。对于指针操作时经常要用到的偏移量增减运算来说,是使用32位整数,还是使用64位整数,或写两套代码?这需要测试后才能决定。
第四、密封类(sealed)。听说密封类能提高性能,我们可以测试一下。有两种测试方式,一是为原来的派生类增加sealed关键字,二是专门另外写一个密封类。我决定同时使用这两种方法,分别测试其性能。


一、测试代码


  测试代码如下——

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
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
 
}

 

二、测试环境


  编译器——
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 (DDR3-1066)


  机器B——
DELL Latitude E6320 
处理器:Intel i3-2310M(2.1GHz, 3MB L3)
内存容量:4GB (DDR3-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)。




三、硬编码与静态调用 的测试结果(栈变量、栈分配、64位整数)



  因为硬编码与静态调用很可能会被执行函数展开优化,速度明显比其他测试项目要快。所我另外写了一个测试函数(TryItStatic),将循环次数设为原来的10倍。


  测试结果如下(单位:毫秒)——

模式A_2005A_2010B_2005B_2010B64_2005B64_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




  结果分析——
先看32位与64位的区别。发现在大多数情况,32位与64位的速度是一样的。唯一就是64位整数运算代码在“64位平台+VS2010”上运行时,速度比在32位下还慢,尤其是静态调用慢了好几倍,硬编码代码的速度也有所下降。真的很奇怪,既然运行的是同一份程序,为什么64位比32位还慢,难道是.Net 4.0在x64平台上的即时编译器的问题?不解。
栈变量、栈分配、静态变量的访问速度几乎一致,看来可以放心地随意使用。


  看来以后写指针操作代码时,只写64位整数版就行了。




四、密封类 的测试结果



  测试结果如下(单位:毫秒)——
模式 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
接口泛型调用密封类的接口: 1402808171995816351637
接口泛型调用结构体的接口: 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)优化,与“硬编码”一样快,快于派生类。
“接口调用”、“泛型调用接口”时与派生类性能一致,快于结构体的“接口调用”。
唯一就是在“泛型调用”时,落后于结构体,与派生类差不多稍微慢一点。
再就是奇怪的“64位平台+VS2010”问题,密封类、结构体在直接调用时,还不如派生类。


  最后总结一下可能会被内联优化的调用类型——
32位平台+VS2005:调用密封类、调用结构体。
32位平台+VS2010:调用密封类、调用结构体、接口约束泛型调用结构体。
64位平台+VS2005:调用密封类、调用结构体。
64位平台+VS2010:(无)。




(完)



测试程序exe——
http://115.com/file/e6ymd5fe
http://download.csdn.net/detail/zyl910/3619643


源代码下载——
http://115.com/file/aqz167n9
http://download.csdn.net/detail/zyl910/3619647


目录——
C#类与结构体究竟谁快——各种函数调用模式速度评测:http://www.cnblogs.com/zyl910/archive/2011/09/19/2186623.html
再探C#类与结构体究竟谁快——考虑栈变量、栈分配、64位整数、密封类:http://www.cnblogs.com/zyl910/archive/2011/09/20/2186622.html
三探C#类与结构体究竟谁快——MSIL(微软中间语言)解读:http://www.cnblogs.com/zyl910/archive/2011/09/24/2189403.html
四探C#类与结构体究竟谁快——跨程序集(assembly)调用:http://www.cnblogs.com/zyl910/archive/2011/10/01/2197844.html

posted on   zyl910  阅读(922)  评论(1编辑  收藏  举报
编辑推荐:
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· C++代码改造为UTF-8编码问题的总结
阅读排行:
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
点击右上角即可分享
微信分享提示