简体   繁体   English

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

[英]Is passing a struct value to a method by-reference in C# an acceptable optimization?

Say I have a struct: 说我有一个结构:

struct MyStruct
{
    public int X
    public int Y
}

And a method in some class that is iterated over many times elsewhere: 并且在某些类中的方法在其他地方多次迭代:

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

Is changing the MyMethod signature to the following an acceptable optimization? 是否将MyMethod签名更改为以下可接受的优化?

public bool MyMethod( ref MyStruct myStruct )

If so, how much of an advantage would it really be? 如果是这样,它真的有多大的优势? If not, about how many fields would a struct need for a big enough advantage using ref this way? 如果没有,那么结构需要多少字段才能以这种方式使用ref足够大的优势?

You'd be making a change to push 8 bytes of data instead of 4, on a 32-bit system. 在32位系统上,您将进行更改以推送8个字节的数据而不是4个字节。 No change in amount of data pushed on a 64-bit system. 在64位系统上推送的数据量没有变化。 You are also adding a requirement to the compiler/JITter that the struct must exist in memory since you are going to be taking the address of it, which may negate other optimizations. 您还要向编译器/ JITter添加一个要求结构必须存在于内存中的要求,因为您将获取它的地址,这可能会否定其他优化。

I doubt this will show any performance increase in your program. 我怀疑这会显示你的程序性能有任何提升。 Profile first and see if MyMethod is even a bottleneck in your program. 首先介绍一下,看看MyMethod是否是您程序中的瓶颈。

Then, presuming there are no other optimization opportunities in MyMethod, make the change to pass by ref, and profile again to see if there is any improvement. 然后,假设MyMethod中没有其他优化机会,请将更改传递给ref,然后再次进行配置以查看是否有任何改进。

Since you explicitly asked whether it was “acceptable” … 既然你明确询问它是否“可以接受”......

I'd answer no . 我回答 By passing the argument by ref , you're lying to the compiler and programmer; 通过ref传递参数,你对编译器和程序员撒谎; ref in .NET (exclusively) means that you intend to modify the argument inside the method. .NET中的ref (独占)意味着您打算修改方法内的参数。

Of course, you could provide an additional comment explaining the “lie” to the programmer (but not to the compiler … ). 当然,你可以提供一个额外的注释来解释程序员的“谎言”(但不是编译器......)。 But why abuse the semantics in the first place? 但为什么首先滥用语义?

If you really need such extreme micro-optimizations (and see the other answers – any performance advantage is questionable for any number of reasons!) .NET may just be the wrong environment. 如果你真的需要这样的极端微优化(并且看到其他答案 - 任何性能优势都会因为各种原因而受到质疑!).NET可能只是错误的环境。 Implement the relevant part in C++. 在C ++中实现相关部分。

Not likely, given your example. 根据你的例子,不太可能。 On a 64-bit processor, the structure will fit comfortably in registers, it won't be passed through the stack. 在64位处理器上,该结构可以很好地适应寄存器,不会通过堆栈传递。 Albeit not on a 32-bit processor and an instance method. 虽然不是32位处理器和实例方法。 When you pass by reference, you're paying for accessing the structure members, an extra pointer dereference is required. 当您通过引用传递时,您需要为访问结构成员付费,需要额外的指针取消引用。 This can get to be more expensive then avoiding the copy, ymmv. 这可能会比避免副本ymmv更昂贵。

The payoff typically starts when the structure is more than 16 bytes. 当结构超过16个字节时,支付通常开始。 One reason for the common guidance to switch to a class when the structure gets larger than that. 当结构变大时,共同指导切换到类的一个原因。 Given that this completely depends on usage, you'll either have to analyze your code and read the assembly (release build of course) or use a profiler. 鉴于这完全取决于使用情况,您要么必须分析代码并阅读程序集(当然是发布版本)或使用分析器。 The profiler isn't that likely to show a difference. 分析器不太可能显示出差异。 It is usually pretty hard to measure a nanosecond unless you artificially do it a billion times. 测量纳秒通常很难,除非你人为地做了十亿次。

With two int fields, the advantage will be extremely small, very unlikely to make a difference. 有两个int字段,优势将非常小,不太可能有所作为。 It might not make any difference at all. 它根本没有任何区别。

Once you start adding more than two Int fields, that advantage starts to go up. 一旦开始添加两个以上的Int字段,这个优势就会开始上升。 Still, not enough to matter unless you're calling that method a lot . 尽管如此,不足以事,除非你调用一个方法很多

In general I would say no: stick with a class with properties. 一般来说,我会说不:坚持使用具有属性的类。 However, there are circumstances that might call for something like this - in particular on compact-framework (think: XNA) or micro-framework. 但是,有些情况可能需要这样的东西 - 特别是在紧凑框架(思考:XNA)或微框架上。 In both cases the GC is very different, and object allocations (and non-deterministic collection) may have a significant impact on the application. 在这两种情况下,GC都非常不同,对象分配(和非确定性收集)可能会对应用程序产生重大影响。

In such cases it is not unheard of to see more structs come into play, and the ref avoids the common "lost update" problems (in most .NET, structs should be immutable; again, XNA does have some scenarios that make it tempting to break this rule). 在这种情况下,看到更多的结构发挥作用并不是闻所未闻的,并且ref避免了常见的“丢失更新”问题(在大多数 .NET中,结构应该是不可变的;再次,XNA 确实有一些场景使得它很有吸引力打破这个规则)。 Another approach of course is to accept and return the data - then the type can be immutable. 另一种方法当然是接受并返回数据 - 然后类型可以是不可变的。

If you mean the performance of passing the object; 如果你的意思是传递对象的表现; then you have to profile on the exact setup you intend using. 那么你必须描述你想要使用的确切设置。 x86 vs x64 is the obvious difference, but there are more. x86 vs x64是明显的区别,但还有更多。 For example, using ref demands that a value is in either a field or a local variable - but many of the JIT performance tweaks on structs work on the head of the stack - meaning you might have a lot more "ldloc" / "stloc" than you strictly need. 例如,使用ref要求值在字段或局部变量中 - 但结构上的许多JIT性能调整都在堆栈的头部工作 - 这意味着你可能有更多“ldloc”/“stloc”比你严格需要的。 You also introduce an extra dereference. 您还引入了一个额外的解引用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM