在C#中将结构值传递给方法by-reference是可接受的优化吗?

时间:2010-05-25 16:12:43

标签: c# .net optimization class-design

说我有一个结构:

struct MyStruct
{
    public int X
    public int Y
}

某个类中的方法在其他地方多次迭代:

public bool MyMethod( MyStruct myStruct )
{
    return ...
}

将MyMethod签名更改为以下可接受的优化吗?

public bool MyMethod( ref MyStruct myStruct )

如果是这样,它真正有多大的优势?如果没有,那么使用ref这种方式,结构需要多少字段以获得足够大的优势?

5 个答案:

答案 0 :(得分:7)

在32位系统上,您将进行更改以推送8个字节的数据而不是4个字节。在64位系统上推送的数据量没有变化。您还要向编译器/ JITter添加一个要求结构必须存在于内存中的要求,因为您将获取它的地址,这可能会否定其他优化。

我怀疑这会显示您的计划中的任何性能提升。首先介绍一下,看看MyMethod是否是你程序中的瓶颈。

然后,假设MyMethod中没有其他优化机会,请将更改传递给ref,然后再次进行配置以查看是否有任何改进。

答案 1 :(得分:4)

既然你明确询问它是否“可以接受”......

我会回答没有。通过ref传递参数,你对编译器和程序员撒谎; .NET中的ref(独占)意味着您打算修改方法内的参数。

当然,你可以提供一个额外的评论来解释程序员的“谎言”(但不是编译器......)。但为什么首先滥用语义?

如果你真的需要这种极端的微优化(并且看到其他答案 - 任何性能优势都有可能因为多种原因而受到质疑!).NET可能只是错误的环境。在C ++中实现相关部分。

答案 2 :(得分:2)

根据你的例子,不太可能。在64位处理器上,该结构可以很好地适应寄存器,不会通过堆栈传递。虽然不是32位处理器和实例方法。当您通过引用传递时,您需要为访问结构成员付费,需要额外的指针取消引用。这可能会比避免副本更加昂贵,ymmv。

支付通常在结构超过16个字节时开始。当结构变大时,共同指导切换到类的一个原因。鉴于这完全取决于使用情况,您要么必须分析代码并阅读程序集(当然是发布版本)或使用分析器。分析器不太可能显示出差异。通常很难测量纳秒,除非你人为地做了十亿次。

答案 3 :(得分:0)

有两个int字段,优势将非常小,不太可能产生影响。它可能没有任何区别。

一旦开始添加两个以上的Int字段,这个优势就会开始上升。但是,除非你正在调用很多的方法,否则不够重要。

答案 4 :(得分:0)

general 中我会说不:坚持使用属性的类。但是,有些情况可能会调用类似的东西 - 特别是在紧凑框架(思考:XNA)或微框架上。在这两种情况下,GC 非常不同,对象分配(和非确定性集合)可能会对应用程序产生重大影响。

在这种情况下,看到更多的结构发挥作用并不是闻所未闻的,ref避免了常见的“丢失更新”问题(在大多数 .NET中,结构应该是不可变的;再一次,XNA 确实有一些场景让它很有可能违反这个规则)。另一种方法当然是接受并返回数据 - 然后类型可以是不可变的。

如果你的意思是传递物体的表现;那么你来描述你想要使用的确切设置。 x86 vs x64是明显的区别,但还有更多。例如,使用ref要求值在字段或局部变量中 - 但结构上的许多JIT性能调整都在堆栈的头部工作 - 这意味着你可能有更多的“ldloc” /“stloc”比你严格需要的。你还引入了一个额外的解引用。