在 C# 中使用参数的成本
有人对在 C# 中使用 params 进行方法参数传递有建议吗?我正在考虑使用 params 功能对前 6 个参数进行重载,然后对第 7 个参数进行重载。我的理由是避免参数功能所需的额外数组分配。这是针对一些高性能实用方法的。有什么建议吗?创建所有重载是否浪费代码?
Does anyone have advice for using the params in C# for method argument passing. I'm contemplating making overloads for the first 6 arguments and then a 7th using the params feature. My reasoning is to avoid the extra array allocation the params feature require. This is for some high performant utility methods. Any advice? Is it a waste of code to create all the overloads?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
老实说,我对每个人都喊“过早优化!”感到有点困扰。原因如下。
string.Format
或Console.WriteLine
的所有重载。此外,即使您分析了两种方法的结果并且发现速度上只有很小的差异,但仍然存在内存分配问题。为每个方法调用创建一个新数组需要分配更多内存,稍后需要对这些内存进行垃圾收集。在某些需要“近乎”实时行为的场景中(例如算法交易,我所在的领域),最小化垃圾收集与最大化执行速度同样重要。
所以,即使它给我带来了一些反对票:我还是说继续吧。
(对于那些声称“编译器肯定已经做了类似的事情”的人——我不太确定。首先,如果是这样的话,我不明白为什么 BCL 类会遵循这种模式,因为我已经但更重要的是,接受多个参数的方法和接受数组的方法之间存在很大的语义差异,因为一个可以< /em> 用作另一个的替代品并不意味着编译器会或应该尝试这样的替代)。
Honestly, I'm a little bothered by everyone shouting "premature optimization!" Here's why.
string.Format
orConsole.WriteLine
.Also, even if you profiled the results of both approaches and saw only a very small difference in speed, there's still the issue of memory allocation. Creating a new array for every method call entails allocating more memory that will need to be garbage collected later. And in some scenarios where "nearly" real-time behavior is desired (such as algorithmic trading, the field I'm in), minimizing garbage collections is just as important as maximizing execution speed.
So, even if it earns me some downvotes: I say go for it.
(And to those who claim "the compiler surely already does something like this"--I wouldn't be so sure. Firstly, if that were the case, I fail to see why BCL classes would follow this pattern, as I've already mentioned. But more importantly, there is a very big semantic difference between a method that accepts multiple arguments and one that accepts an array. Just because one can be used as a substitute for the other doesn't mean the compiler would, or should, attempt such a substitution).
是的,这就是 .NET 框架使用的策略。 String.Concat() 就是一个很好的例子。它具有最多 4 个字符串的重载,以及一个采用参数 string[] 的后备字符串。在这里非常重要的是,Concat 需要足够快,并且当用户使用 + 运算符而不是 StringBuilder 时,它可以帮助用户落入成功的陷阱。
您将得到的代码重复就是价格。您可以对它们进行分析,看看加速是否值得为维护带来麻烦。
Fwiw:.NET 框架中有很多这样的微优化。有点必要,因为设计者无法真正预测他们的类将如何使用。 String.Concat() 很可能用在对程序性能至关重要的紧密内部循环中,就像只在启动时运行一次的配置读取器一样。作为您自己代码的最终用户,您通常不必担心这一点。反之亦然,.NET 框架代码明显没有进行微优化,而它们的好处不太可能是可衡量的。就像当核心代码很慢时提供重载一样。
Yes, that's the strategy that the .NET framework uses. String.Concat() would be a good example. It has overloads for up to 4 strings, plus a fallback one that takes a params string[]. Pretty important here, Concat needs to be fast and is there to help the user fall in the pit of success when he uses the + operator instead of a StringBuilder.
The code duplication you'll get is the price. You'd profile them to see if the speedup is worth the maintenance headache.
Fwiw: there are plenty of micro-optimizations like this in the .NET framework. Somewhat necessary because the designers could not really predict how their classes were going to be used. String.Concat() is just as likely to be used in a tight inner loop that is critical to program perf as, say, a config reader that only runs once at startup. As the end-user of your own code, you typically have the luxury of not having to worry about that. The reverse is also true, the .NET framework code is remarkably free of micro-optimizations when it is unlikely that their benefit would be measurable. Like providing overloads when the core code is slow anyway.
您始终可以将
Tuple
传递为参数,或者如果参数的类型始终相同,则为IList
。正如其他答案和评论所说,您应该只在以下情况下进行优化:
You can always pass
Tuple
as a parameter, or if the types of the parameters are always the same, anIList<T>
.As other answers and comments have said, you should only optimize after:
我的观点是,如果您的方法能够获取无限数量的参数,那么它内部的逻辑就以数组样式工作。因此,重载有限数量的参数不会有帮助。除非,您可以以更快的方式以完全不同的方式实现有限数量的参数。
例如,如果您将参数传递给 Console.WriteLine,那么其中也会创建一个隐藏的数组,因此无论哪种方式,您最终都会得到一个数组。
而且,很抱歉打扰丹涛,我也觉得这是不成熟的优化。因为您需要知道参数数量有限的重载会产生什么区别。如果您的应用程序对性能至关重要,那么您需要实现这两种方法并尝试运行测试并比较执行时间。
My point is, if your method is capable of getting unlimited number of parameters, then the logic inside it works in an array-style. So, having overloads for limited number of parameters wouldn't be helping. Unless, you can implement limited number of parameters in a whole different way that is much faster.
For example, if you're handing the parameters to a Console.WriteLine, there's a hidden array creation in there too, so either way you end up having an array.
And, sorry for bothering Dan Tao, I also feel like it is premature optimization. Because you need to know what difference would it make to have overloads with limited number of parameters. If your application is that much performance-critical, you'd need to implement both ways and try to run a test and compare execution times.
这个阶段就别想表现了。创建任何重载将使您的代码在两年后的凌晨 4 点更易于编写和理解。有时这意味着参数,有时这意味着避免它。
当你得到一些可行的东西后,弄清楚这些是否是性能问题。让参数变得更复杂并不难,但如果现在添加不必要的复杂性,以后就永远不会让它们变得更复杂。
Don't even think about performance at this stage. Create whatever overloads will make your code easier to write and easier to understand at 4am two years from now. Sometimes that means params, sometimes that means avoiding it.
After you've got something that works, figure out if these are a performance problem. It's not hard to make the parameters more complicated, but if you add unnecessary complexity now, you'll never make them less so later.
您可以尝试使用this之类的方法来对性能进行基准测试,以便获得一些具体的数字与做出决定。
一般来说,对象分配比 C/C++ 稍快,而小对象的删除要快得多——直到每秒生成数万个对象。这是一篇关于内存分配性能的旧文章。
You can try something like this to benchmark the performance so you have some concrete numbers to make decisions with.
In general, object allocation is slightly faster than in C/C++ and deletion is much, much faster for small objects -- until you have tens of thousands of them being made per second. Here's an old article regarding memory allocation performance.