我在XNA中闲逛,发现其中的Vector3类是使用公共字段而不是属性.我尝试了一个快速的基准测试,并发现,struct差异非常大(将两个向量组合在一起,1亿次带有2.0s属性和1.4s带字段).对于参考类型,差异似乎并不大,但它存在.
那为什么呢?我知道属性被编译成get_X和set_X方法,这会导致方法调用开销.但是,这些简单的getter/setter是不是总是被JIT内联?我知道你无法保证JIT决定做什么,但肯定这在概率列表中相当高?还有什么将公共领域与机器级别的财产分开?
有一点我一直想知道:自动实现的属性(public int Foo { get; set; })比公共领域"更好"的OO设计?或者更好地说:那两个有什么不同?我知道用反射把它变成一个属性更容易,但其他什么呢?我打赌这两个问题的答案是一回事.
BTW:我使用.NET 3.5 SP1,我相信固定的问题,其中有结构的方法(或方法的结构,我不知道)均未成行,所以这不是它.我认为我至少使用它,它肯定安装但是再次,我使用Vista 64位SP1应该有DX10.1,除了我没有DX10.1 ..
另外:是的,我一直在运行发布版本:)
编辑:我很欣赏的快速解答的家伙,但我指出,我不知道,一个属性访问是一个方法调用,但我不知道为什么,大概是,在林立的方法比直接字段访问速度较慢.
编辑2:所以我创建了另一个struct使用显式GetX()方法(o我怎么不完全错过我的Java时间),并且无论我是否禁用内嵌(通过),都执行相同的操作[MethodImplAttribute(MethodImplOptions.NoInlining)],所以结论:非静态方法显然从未内联,甚至不在结构上.
我认为有异常,JIT可以选择虚拟方法调用.为什么不能在没有继承的结构上发生这种情况,因此方法调用只能指向一种可能的方法,对吧?或者是因为你可以在它上面实现一个接口?
这是一种耻辱,因为它真的会让我考虑在性能关键的东西上使用属性,但使用字段会让我觉得很脏,我不妨写下我在C中做的事情.
编辑3:我发现这篇文章的主题完全相同.他的最终结论是,财产电话确实被优化了.我也可以发誓我已经多次阅读过简单的getter/setter属性会被内联,尽管callvirt在IL中.我疯了吗?
编辑4:Reed Copsey在下面的评论中发布了答案:
Re:Edit3 - 看我更新的评论:我相信这是x86 JIT vs x64 JIT问题.x64中的JIT不够成熟.随着越来越多的64位系统每天上线,我希望MS能够迅速提高. - 里德·科普塞
我回答他的回答:
谢谢,这就是答案!我尝试强制x86构建,所有方法都同样快,并且比x64快得多.实际上这对我来说非常令人震惊,我不知道我是在64位操作系统上生活在石器时代.我会在你的答案中包含你的评论,以便更好. - 朱利安
感谢大家!
在你对肠道作出反应之前,正如我最初所做的那样,请阅读整个问题.我知道他们让你感觉很脏,我知道我们以前都被烧过,我知道这不是"好风格",但公共场地还好吗?
我正在研究一个相当大规模的工程应用程序,它创建并使用结构的内存模型(从高层建筑到桥梁到棚子,无关紧要).该项目涉及TON的几何分析和计算.为了支持这一点,该模型由许多微小的不可变只读结构组成,用于表示点,线段等事物.这些结构的某些值(如点的坐标)可被访问数十亿或数亿典型程序执行期间的时间.由于模型的复杂性和计算量,性能绝对至关重要.
我觉得我们正在尽我们所能优化我们的算法,性能测试以确定瓶颈,使用正确的数据结构等.我不认为这是过早优化的情况.性能测试显示直接访问字段而不是通过对象上的属性时性能提升的数量级(至少).鉴于此信息,以及我们还可以公开与属性相同的信息以支持数据绑定和其他情况......这样可以吗? 请记住,只读取不可变结构上的字段. 任何人都可以想到我会后悔的原因吗?
这是一个示例测试应用程序:
struct Point {
public Point(double x, double y, double z) {
_x = x;
_y = y;
_z = z;
}
public readonly double _x;
public readonly double _y;
public readonly double _z;
public double X { get { return _x; } }
public double Y { get { return _y; } }
public double Z { get { return _z; } }
}
class Program {
static void Main(string[] …Run Code Online (Sandbox Code Playgroud) 我在某个地方读到,拥有公共财产比在一个班级中拥有公共成员更可取.
这只是因为抽象和模块化吗?还有其他任何超越原因吗?
属性访问由编译器转换为函数调用.对于没有备份存储的属性(例如public string UserName { get; set; }),与直接成员访问相比,性能开销会是多少?(我知道它通常不会有所作为,但在我的一些代码中,属性被访问了数百万次.)
Edit1:我在整数成员和属性上运行了一些测试代码,公共成员的速度是属性的3-4倍.(在调试中~57 ms.vs~206 ms.在Release中57与97 vs. 97是最常见的运行值).对于1000万次读写,两者都足够小,不足以证明改变任何东西.
码:
class TestTime1
{
public TestTime1() { }
public int id=0;
}
class TestTime2
{
public TestTime2() { }
[DefaultValue(0)]
public int ID { get; set; }
}
class Program
{
static void Main(string[] args)
{
try
{
TestTime1 time1 = new TestTime1();
TestTime2 time2 = new TestTime2();
Stopwatch watch1 = new Stopwatch();
Stopwatch watch2 = new Stopwatch();
watch2.Start();
for (int i = 0; …Run Code Online (Sandbox Code Playgroud) 所以,我在摆弄和学习反思时遇到了一个奇怪的问题.我正在尝试更改一个私有的readonly字段,如下所示:
public class A
{
private static readonly int x;
public int X
{
get { return x; }
}
}
static void Main(string[] args)
{
A obj = new A();
Type objType = typeof(A);
Console.WriteLine(obj.X);
FieldInfo objField = objType.GetField("x", BindingFlags.Static | BindingFlags.NonPublic);
objField.SetValue(null, 100);
Console.WriteLine(obj.X);
Console.ReadLine();
}
Run Code Online (Sandbox Code Playgroud)
如果我按原样运行程序,那么每次都会打印0到控制台.但是,如果我注释掉第一个印刷品,那么第二个印刷品会写出预期的100个印刷品.
谁可以了解这里发生的事情?谢谢!
编辑:扼杀它似乎在Visual Studio 2012中工作,但不是在2010年.据我所知,两者的设置是相同的.
编辑2:使用平台目标x64构建时工作,而不是使用x86.猜猜新问题是:为什么?
编辑3:在反汇编中比较x64和x86版本; 在x86版本中似乎有一些内联.
编辑4:哦,我想我已经弄清楚发生了什么,有点像.我不认为A类中的属性是内联的问题.我相信当在main方法中第二次读取属性时,属性调用被优化掉了(后备字段应该是readonly,值应该相同)并且旧值被重用.这至少是我的"理论".
c# ×5
.net ×2
performance ×2
field ×1
inlining ×1
oop ×1
optimization ×1
properties ×1
readonly ×1
reflection ×1
struct ×1