26

有没有人建议在 C# 中使用参数传递方法参数。我正在考虑对前 6 个参数进行重载,然后使用 params 功能对第 7 个参数进行重载。我的理由是避免 params 功能所需的额外数组分配。这适用于一些高性能的实用方法。有什么建议吗?创建所有重载是否浪费代码?

4

6 回答 6

67

老实说,大家都在喊“过早的优化”,我有点烦。这就是为什么。

  1. 你说的很有道理,特别是当你已经表明你正在开发一个高性能库时。
  2. 甚至 BCL 类也遵循这种模式。考虑string.Formator的所有重载Console.WriteLine
  3. 很容易搞定反对过早优化运动背后的整个前提是,当您为了优化性能而做一些棘手的事情时,您很可能会意外破坏某些东西并降低您的代码可维护性。我看不出这里有什么危险。对于您自己以及任何可能处理您的代码的未来开发人员来说,您正在做的事情应该非常简单。

此外,即使您分析了这两种方法的结果并且只看到了非常小的速度差异,仍然存在内存分配问题。为每个方法调用创建一个新数组需要分配更多内存,以后需要进行垃圾回收。在某些需要“近乎”实时行为的场景中(例如算法交易,所在的领域),最小化垃圾收集与最大化执行速度同样重要。

所以,即使它为我赢得了一些反对票:我说去吧。

(对于那些声称“编译器肯定已经做了这样的事情”的人——我不太确定。首先,如果是这样的话,我不明白为什么 BCL 类会遵循这种模式,因为我已经已经提到了。但更重要的是,接受多个参数的方法和接受数组的方法之间存在很大的语义差异。仅仅因为一个可以用作另一个的替代品并不意味着编译器会或应该,尝试这样的替换)。

于 2010-10-16T20:27:16.847 回答
15

是的,这就是 .NET 框架使用的策略。String.Concat() 就是一个很好的例子。它具有最多 4 个字符串的重载,以及一个带有参数 string[] 的后备字符串。在这里非常重要,Concat 需要快速,并且当用户使用 + 运算符而不是 StringBuilder 时,它可以帮助用户陷入成功的陷阱。

您将获得的代码重复就是价格。您将对其进行分析,以查看加速是否值得维护头痛。

Fwiw:.NET 框架中有很多这样的微优化。有点必要,因为设计师无法真正预测他们的类将如何被使用。String.Concat() 很可能用在对程序性能至关重要的紧密内部循环中,例如,只在启动时运行一次的配置读取器。作为您自己代码的最终用户,您通常可以不必担心这一点。反之亦然,.NET 框架代码明显没有微优化,而它们的好处不太可能是可衡量的。就像在核心代码很慢时提供重载一样。

于 2010-10-16T20:27:30.140 回答
4

您始终可以Tuple作为参数传递,或者如果参数的类型始终相同,则使用IList<T>.

正如其他答案和评论所说,您应该只在以下情况下进行优化:

  1. 确保行为正确。
  2. 确定优化的需要
于 2010-10-16T20:12:40.203 回答
2

我的观点是,如果您的方法能够获取无限数量的参数,那么它内部的逻辑以数组样式运行。因此,对有限数量的参数进行重载将无济于事。除非,您可以以更快的方式以完全不同的方式实现有限数量的参数。

例如,如果您将参数传递给 Console.WriteLine,那么其中也会创建一个隐藏的数组,因此无论哪种方式,您最终都会拥有一个数组。

还有,不好意思打扰了丹涛,我也觉得是过早的优化。因为您需要知道使用有限数量的参数进行重载会有什么不同。如果您的应用程序对性能非常关键,那么您需要实现这两种方式并尝试运行测试并比较执行时间。

于 2010-10-16T20:46:11.480 回答
1

甚至不要考虑现阶段的表现。在两年后的凌晨 4 点,创建任何能让你的代码更容易编写和更容易理解的重载。有时这意味着参数,有时这意味着避免它。

在你得到一些有用的东西之后,找出这些是否是性能问题。让参数变得更复杂并不难,但如果你现在增加不必要的复杂性,以后你永远不会让它们变得更简单。

于 2010-10-16T20:14:07.050 回答
1

您可以尝试这样方法来对性能进行基准测试,这样您就有一些具体的数字可以用来做决定。

一般来说,对象分配比 C/C++ 中的稍快,而小对象的删除速度要快得多——直到每秒生成数万个对象。这是一篇关于内存分配性能的旧文章。

于 2010-10-16T20:46:08.983 回答