I have a function that I use to add vectors, like this:
我有一个函数,我用来添加向量,像这样:
public static Vector AddVector(Vector v1, Vector v2)
{
return new Vector(
v1.X + v2.X,
v1.Y + v2.Y,
v1.Z + v2.Z);
}
Not very interesting. However, I overload the '+' operator for vectors and in the overload I call the AddVector function to avoid code duplication. I was curious whether this would result in two method calls or if it would be optimized at compile or JIT time. I found out that it did result in two method calls because I managed to gain 10% in total performance by duplicating the code of the AddVector as well as the dot product method in the '+' and '*' operator overload methods. Of course, this is a niche case because they get called tens of thousands of times per second, but I didn't expect this. I guess I expected the method to be inlined in the other, or something. And I suppose it's not just the overhead of the method call, but also the copying of the method arguments into the other method (they're structs).
不是很有趣。但是,我为向量重载'+'运算符,在重载中我调用AddVector函数以避免代码重复。我很好奇这是否会导致两个方法调用,或者它是否会在编译或JIT时优化。我发现它确实导致了两个方法调用,因为我通过复制AddVector的代码以及'+'和'*'运算符重载方法中的点积方法,总共获得了10%的性能。当然,这是一个利基案例,因为它们被称为每秒数万次,但我没想到这一点。我想我希望这个方法可以在另一个方面内联,或者其他东西。我想这不仅仅是方法调用的开销,还包括将方法参数复制到另一个方法中(它们是结构)。
It's no big deal, I can just duplicate the code (or perhaps just remove the AddVector method since I never call it directly) but it will nag me a lot in the future when I decide to create a method for something, like splitting up a large method into several smaller ones.
这没什么大不了的,我可以复制代码(或者只是删除AddVector方法,因为我从来没有直接调用它)但是当我决定为某些东西创建一个方法时,它将会惹恼我很多,比如分裂一个大方法分成几个较小的方法。
6 个解决方案
#1
Don't assume that struct
is the right choice for performance. The copying cost can be significant in some scenarios. Until you measure you don't know. Furthermore, struct
s have spooky behaviors, especially if they're mutable, but even if they're not.
不要认为struct是性能的正确选择。在某些情况下,复制成本可能很高。直到你衡量你不知道。此外,结构具有怪异的行为,特别是如果它们是可变的,但即使它们不是。
In addition, what others have said is correct:
此外,其他人所说的是正确的:
- Running under a debugger will disable JIT optimizations, making your performance measurements invalid.
- Compiling in Debug mode also makes performance measurements invalid.
在调试器下运行将禁用JIT优化,使您的性能测量无效。
在调试模式下编译也会使性能测量无效。
#2
If you compile into debug mode or begin the process with a debugger attatched (though you can add one later) then a large class of JIT optimisations, including inlining, won't happen.
如果你编译成调试模式或者在调试器附加的情况下开始这个过程(虽然你可以稍后添加一个),那么就不会发生大量的JIT优化,包括内联。
Try re-running your tests by compiling it in Release mode and then running it without a debugger attatched (Ctrl+F5 in VS) and see if you see the optimisations you expected.
尝试通过在发布模式下编译它来重新运行测试,然后在没有调试器的情况下运行它(VS中的Ctrl + F5)并查看是否看到了预期的优化。
#3
"And I suppose it's not just the overhead of the method call, but also the copying of the method arguments into the other method (they're structs)."
“我认为这不仅仅是方法调用的开销,而且还是将方法参数复制到另一个方法中(它们是结构)。”
Why don't you test this out? Write a version of AddVector that takes a reference to two vector structs, instead of the structs themselves.
你为什么不试试这个?编写一个AddVector版本,它引用两个向量结构,而不是结构本身。
#4
I had VS in Release mode and I ran without debugging so that can't be to blame. Running the .exe in the Release folder yields the same result. I have .NET 3.5 SP1 installed.
我在发布模式下安装了VS而没有调试就跑了,所以不能怪。在Release文件夹中运行.exe会产生相同的结果。我安装了.NET 3.5 SP1。
And whether or not I use structs depends on how many I create of something and how large it is when copying versus referencing.
而且我是否使用结构取决于我创建的东西的数量以及复制与引用时的大小。
#5
You say Vector
is a struct. According to a blog post from 2004, value types are a reason for not inlining a method. I don't know whether the rules have changed about that in the meantime.
你说Vector是一个结构。根据2004年的博客文章,价值类型是不内联方法的原因。我不知道规则是否在此期间发生了变化。
#6
Theres only one optimization I can think of, maybe you want to have a vOut parameter, so you avoid the call to new() and hence reduce garbage collection - Of course, this depends entirely on what you are doing with the returned vector and if you need to persist it or not, and if you're running into garbage collection problems.
我只能想到一个优化,也许你想要一个vOut参数,所以你避免调用new(),从而减少垃圾收集 - 当然,这完全取决于你对返回的向量做了什么,如果你需要坚持或不坚持,如果你遇到垃圾收集问题。
#1
Don't assume that struct
is the right choice for performance. The copying cost can be significant in some scenarios. Until you measure you don't know. Furthermore, struct
s have spooky behaviors, especially if they're mutable, but even if they're not.
不要认为struct是性能的正确选择。在某些情况下,复制成本可能很高。直到你衡量你不知道。此外,结构具有怪异的行为,特别是如果它们是可变的,但即使它们不是。
In addition, what others have said is correct:
此外,其他人所说的是正确的:
- Running under a debugger will disable JIT optimizations, making your performance measurements invalid.
- Compiling in Debug mode also makes performance measurements invalid.
在调试器下运行将禁用JIT优化,使您的性能测量无效。
在调试模式下编译也会使性能测量无效。
#2
If you compile into debug mode or begin the process with a debugger attatched (though you can add one later) then a large class of JIT optimisations, including inlining, won't happen.
如果你编译成调试模式或者在调试器附加的情况下开始这个过程(虽然你可以稍后添加一个),那么就不会发生大量的JIT优化,包括内联。
Try re-running your tests by compiling it in Release mode and then running it without a debugger attatched (Ctrl+F5 in VS) and see if you see the optimisations you expected.
尝试通过在发布模式下编译它来重新运行测试,然后在没有调试器的情况下运行它(VS中的Ctrl + F5)并查看是否看到了预期的优化。
#3
"And I suppose it's not just the overhead of the method call, but also the copying of the method arguments into the other method (they're structs)."
“我认为这不仅仅是方法调用的开销,而且还是将方法参数复制到另一个方法中(它们是结构)。”
Why don't you test this out? Write a version of AddVector that takes a reference to two vector structs, instead of the structs themselves.
你为什么不试试这个?编写一个AddVector版本,它引用两个向量结构,而不是结构本身。
#4
I had VS in Release mode and I ran without debugging so that can't be to blame. Running the .exe in the Release folder yields the same result. I have .NET 3.5 SP1 installed.
我在发布模式下安装了VS而没有调试就跑了,所以不能怪。在Release文件夹中运行.exe会产生相同的结果。我安装了.NET 3.5 SP1。
And whether or not I use structs depends on how many I create of something and how large it is when copying versus referencing.
而且我是否使用结构取决于我创建的东西的数量以及复制与引用时的大小。
#5
You say Vector
is a struct. According to a blog post from 2004, value types are a reason for not inlining a method. I don't know whether the rules have changed about that in the meantime.
你说Vector是一个结构。根据2004年的博客文章,价值类型是不内联方法的原因。我不知道规则是否在此期间发生了变化。
#6
Theres only one optimization I can think of, maybe you want to have a vOut parameter, so you avoid the call to new() and hence reduce garbage collection - Of course, this depends entirely on what you are doing with the returned vector and if you need to persist it or not, and if you're running into garbage collection problems.
我只能想到一个优化,也许你想要一个vOut参数,所以你避免调用new(),从而减少垃圾收集 - 当然,这完全取决于你对返回的向量做了什么,如果你需要坚持或不坚持,如果你遇到垃圾收集问题。