简体   繁体   English

在C#中使用params的成本

[英]Cost of using params in C#

Does anyone have advice for using the params in C# for method argument passing. 有没有人建议在C#中使用params进行方法参数传递。 I'm contemplating making overloads for the first 6 arguments and then a 7th using the params feature. 我正在考虑为前6个参数进行重载,然后使用params功能进行7次重载。 My reasoning is to avoid the extra array allocation the params feature require. 我的理由是避免params功能所需的额外数组分配。 This is for some high performant utility methods. 这适用于一些高性能的实用方法。 Any advice? 有什么建议? Is it a waste of code to create all the overloads? 创建所有重载是浪费代码吗?

Honestly, I'm a little bothered by everyone shouting "premature optimization!" 老实说,每个人大喊“过早优化!”我都有点困扰。 Here's why. 这就是原因。

  1. What you say makes perfect sense, particularly as you have already indicated you are working on a high-performance library. 你说的很有道理, 特别是因为你已经表明你正在开发一个高性能的库。
  2. Even BCL classes follow this pattern. 即使是BCL课程也遵循这种模式。 Consider all the overloads of string.Format or Console.WriteLine . 考虑string.FormatConsole.WriteLine所有重载。
  3. This is very easy to get right . 很容易做对 The whole premise behind the movement against premature optimization is that when you do something tricky for the purposes of optimizing performance, you're liable to break something by accident and make your code less maintainable. 针对过早优化的运动背后的整个前提是,当您为了优化性能而做一些棘手的事情时,您可能会意外地破坏某些内容并使您的代码不易维护。 I don't see how that's a danger here; 我不明白这是多么危险; it should be very straightforward what you're doing, to yourself as well as any future developer who may deal with your code. 对于您自己以及可能处理您的代码的任何未来开发人员而言,您应该非常直截了当地做什么。

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). (对那些声称“编译器肯定已经做过类似事情”的人来说 - 我不会那么肯定。首先,如果是这样的话,我不明白为什么BCL课程会遵循这种模式,就像我一样已经提到了。但更重要的是,接受多个参数的方法和接受数组的方法之间存在非常大的语义差异。仅仅因为一个可以用作另一个的替代并不意味着编译器会或者应该 ,尝试这样的替代)。

Yes, that's the strategy that the .NET framework uses. 是的,这是.NET框架使用的策略。 String.Concat() would be a good example. String.Concat()就是一个很好的例子。 It has overloads for up to 4 strings, plus a fallback one that takes a params string[]. 它有多达4个字符串的重载,加上一个带有params字符串[]的后备字符串。 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. 在这里非常重要,Concat需要快速,并且当他使用+运算符而不是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. Fwiw:在.NET框架中有很多这样的微优化。 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. String.Concat()很可能在一个紧密的内部循环中使用,这对于编程性执行是至关重要的,例如,一个只在启动时运行一次的配置阅读器。 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. 反过来也是如此,当.NET框架代码不太可能被测量时,它显然没有微优化。 Like providing overloads when the core code is slow anyway. 就像在核心代码很慢时提供重载一样。

You can always pass Tuple as a parameter, or if the types of the parameters are always the same, an IList<T> . 您始终可以将Tuple作为参数传递,或者如果参数的类型始终相同,则为IList<T>

As other answers and comments have said, you should only optimize after: 正如其他答案和评论所说,你应该只在以下后进行优化:

  1. Ensuring correct behavior. 确保正确的行为。
  2. Determining the need to optimize. 确定优化的必要性

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. 例如,如果您将参数传递给Console.WriteLine,那里也会创建一个隐藏的数组,所以无论哪种方式最终都有一个数组。

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. 如果您的应用程序对性能至关重要,那么您需要实现这两种方法并尝试运行测试并比较执行时间。

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. 创建任何重载将使您的代码更容易编写,并在两年后的凌晨4点更容易理解。 Sometimes that means params, sometimes that means avoiding it. 有时这意味着params,有时这意味着避免它。

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. 让参数变得更复杂并不难,但如果你现在增加不必要的复杂性,你永远不会让它们变得那么简单。

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. 一般来说,对象分配比在C / C ++中稍快一些,对于小对象来说,删除要快得多,直到每秒都有数万个对象被删除。 Here's an old article regarding memory allocation performance . 这是一篇关于内存分配性能的旧文章

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

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