Squ*_*ama 17 .net c# casting interface
我被引导相信在某些情况下,铸造可能成为可衡量的性能障碍.当我们开始处理令人讨厌的异常投掷\捕获的不连贯网络时,情况可能会更多.
鉴于我希望在编程时创建更正确的启发式方法,我已经被提示向.NET专家提出这个问题:接口是否比类型转换更快?
为了给出一个代码示例,让我们说这存在:
public interface IEntity { IParent DaddyMommy { get; } }
public interface IParent : IEntity { }
public class Parent : Entity, IParent { }
public class Entity : IEntity
{
public IParent DaddyMommy { get; protected set; }
public IParent AdamEve_Interfaces
{
get
{
IEntity e = this;
while (e.DaddyMommy != null)
e = e.DaddyMommy as IEntity;
return e as IParent;
}
}
public Parent AdamEve_Classes
{
get
{
Entity e = this;
while (e.DaddyMommy != null)
e = e.DaddyMommy as Entity;
return e as Parent;
}
}
}
Run Code Online (Sandbox Code Playgroud)
那么,AdamEve_Interfaces比AdamEve_Classes快吗?如果是这样,多少钱?而且,如果你知道答案,为什么?
Eri*_*ert 17
这里的一些答案建议基准测试,这是朝着正确方向迈出的一步,但这只是旅程的第一步.
我的团队在这方面做了大量的分析和基准测试.简短版本是肯定的,在某些情况下,接口会产生较小但可衡量的性能成本.然而,实际成本取决于很多因素,包括支持多少接口,给定引用的接口数量,访问模式等等.CLR具有很多启发式功能,旨在加快常见情况下的接口访问速度.
如果您正在对其中一个常见案例进行基准测试,但您的实际程序属于不太常见的情况,那么您的基准测试是有害的,因为它会为您提供误导性数据.
在真实代码上进行真实的性能测量要好得多.使用分析器,双向编写代码,并以可见且与用户相关的方式查看这两种方式是否可测量,重复性更快.
至于你对投掷和捕捉的提及:投掷和捕捉的表现成本应该是无关紧要的.根据定义,例外是例外的,不常见.此外,例外通常表明某些事情很快就会停止; 通常情况下,某些事情是否会尽快停止并不重要.如果您遇到异常门控的情况,那么您需要解决更大的问题:停止抛出这么多异常.抛出的异常应该非常罕见.
看看这里:
http://thatstoday.com/robbanp/blog/6/25/csharp-performance--cast-vs-interface
而且,是的,你似乎是对的.
编辑好吧,似乎我错了.就像我的"patrício"Martinho Fernandes评论一样,上面的链接完全是假的(但为了诚实的编辑,我会把它保留在这里).
我现在有空闲时间,所以我写了一个简单的性能测量代码:
public partial class Form1 : Form
{
private const int Cycles = 10000000;
public interface IMyInterface
{
int SameProperty { get; set; }
}
public class InterfacedClass : IMyInterface
{
public int SameProperty { get; set; }
}
public class SimpleClass
{
public int SameProperty { get; set; }
}
public struct InterfacedStruct : IMyInterface
{
public int SameProperty { get; set; }
}
public struct SimpleStruct
{
public int SameProperty { get; set; }
}
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
var simpleClassTime = MeasureSimpleClass();
var interfacedClassTime = MeasureInterfacedClass();
var simpleStructTime = MeasureSimpleStruct();
var interfacedStructTime = MeasureInterfacedStruct();
var message = string.Format(
"simpleClassTime = {0}\r\ninterfacedClassTime = {1}\r\nsimpleStructTime = {2}\r\ninterfacedStructTime = {3}",
simpleClassTime,
interfacedClassTime,
simpleStructTime,
interfacedStructTime
);
textBox.Text = message;
}
private static long MeasureSimpleClass() {
var watch = Stopwatch.StartNew();
var obj = new SimpleClass();
for (var i = 0; i < Cycles; i++)
{
obj.SameProperty = i;
var j = obj.SameProperty;
obj.SameProperty = j;
}
return watch.ElapsedMilliseconds;
}
private static long MeasureInterfacedClass() {
var watch = Stopwatch.StartNew();
IMyInterface obj = new InterfacedClass();
for (var i = 0; i < Cycles; i++) {
obj.SameProperty = i;
var j = obj.SameProperty;
obj.SameProperty = j;
}
return watch.ElapsedMilliseconds;
}
private static long MeasureSimpleStruct()
{
var watch = Stopwatch.StartNew();
var obj = new SimpleStruct();
for (var i = 0; i < Cycles; i++)
{
obj.SameProperty = i;
var j = obj.SameProperty;
obj.SameProperty = j;
}
return watch.ElapsedMilliseconds;
}
private static long MeasureInterfacedStruct()
{
var watch = Stopwatch.StartNew();
IMyInterface obj = new InterfacedStruct();
for (var i = 0; i < Cycles; i++)
{
obj.SameProperty = i;
var j = obj.SameProperty;
obj.SameProperty = j;
}
return watch.ElapsedMilliseconds;
}
}
Run Code Online (Sandbox Code Playgroud)
结果是:
simpleClassTime = 274
interfacedClassTime = 339
simpleStructTime = 247
interfacedStructTime = 302
Run Code Online (Sandbox Code Playgroud)
我真的曾经认为接口对于class类型会更快,而且速度更慢struct(因为后者涉及装箱/拆箱),但事实并非如此:具体的类/结构参考似乎总是更快.
此外,它可能涉及到谁:我认为性能不是决定是否应该使用接口的良好标准.与其他人所说的不同的是,差别可以忽略不计.
您是否尝试过测试?这是一个运行10,000,000次的循环。在我的机器上,接口版本大约需要440毫秒,而类版本大约需要410毫秒。如此接近,但总体而言,该类版本获胜。
using System;
namespace ConsoleApplication1
{
public interface IEntity { IParent DaddyMommy { get; } }
public interface IParent : IEntity { }
public class Parent : Entity, IParent { }
public class Entity : IEntity
{
public IParent DaddyMommy { get; protected set; }
public IParent AdamEve_Interfaces
{
get
{
IEntity e = this;
while (this.DaddyMommy != null)
e = e.DaddyMommy as IEntity;
return e as IParent;
}
}
public Parent AdamEve_Classes
{
get
{
Entity e = this;
while (this.DaddyMommy != null)
e = e.DaddyMommy as Entity;
return e as Parent;
}
}
}
class Program
{
static void Main(string[] args)
{
Entity X = new Entity();
Parent P;
IParent IP;
System.Diagnostics.Stopwatch ST = new System.Diagnostics.Stopwatch();
Int32 i;
ST.Start();
for (i = 0; i < 10000000; i++)
{
IP = X.AdamEve_Interfaces;
}
ST.Stop();
System.Diagnostics.Trace.WriteLine(ST.ElapsedMilliseconds);
ST.Reset();
ST.Start();
for (i = 0; i < 10000000; i++)
{
P = X.AdamEve_Classes;
}
ST.Stop();
System.Diagnostics.Trace.WriteLine(ST.ElapsedMilliseconds);
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6178 次 |
| 最近记录: |