在循环内外声明变量会影响性能吗?

11

这是什么意思:

foreach(Type item in myCollection)
{
   StringBuilder sb = new StringBuilder();
}

比起其他的方法要慢得多:

StringBuilder sb = new StringBuilder();

foreach(Type item in myCollection)
{
   sb = new StringBuilder();
}

换句话说,我在哪里声明StringBuilder真的很重要吗?


3
类似于https://dev59.com/TXE95IYBdhLWcg3wHqQV。 - Mark Byers
1
一个不相关的错误是第二个版本应该初始化为null,以避免过度分配。 - Steven Sudit
7个回答

15

不会影响性能,不管你在哪里声明它。

为了代码整洁性,在使用它的最内层范围内声明它,例如你的第一个例子。


1
这应该编译成相同的 IL,我想。如果他没有两次初始化 sb 的话,它就会编译成相同的 IL。 - Adam Houldsworth
1
请纠正我,如果您在循环内部声明它,那么它不会在循环外部可用(未声明),对吗? - NullUserException
3
是的,您是正确的。但是如果您在循环之外不需要它,则更清晰的做法是在循环内部声明它。 - sloth

12

如果你这样写,可能会提高一些性能:

StringBuilder sb = new StringBuilder();
foreach(Type item in myCollection)
{
   sb.Length = 0;
}

所以你需要在循环外实例化StringBuilder一次,并在循环中重置大小,这比实例化新对象略快。


1
+1:根据构建字符串的大小和结果内部缓冲区在sb中的大小,这可能会产生可衡量的差异。 - Alex
2
可能会,也可能不会。当你调用 ToString 时,它会复制缓冲区。如果有理由认为它对性能敏感,我会进行基准测试。 - Steven Sudit

2
在第二个例子中,您创建了一个额外的StringBuilder实例。除此之外,它们都是相同的,因此性能问题可以忽略不计。

我认为这应该是对问题的评论。 - Shaihi
@Shaihi - 为什么?w69rdy正在回答这个问题。 - mphair

1

这里的代码不足以清楚地表明在您的特定情况下性能差异。尽管如此,在大多数情况下,像这样在循环内部声明引用变量与在外部声明之间的差异微不足道。


1
你两个代码示例的有效区别在于第二个将比第一个多分配1个StringBuilder实例。与应用程序的其余部分相比,这对性能的影响基本上是微不足道的。

0

最好的方法是在循环中尝试这两种方法,每个循环大约100,000次。测量每个100,000次迭代所需的时间并进行比较。我认为差别不大。 但是,确实存在一些小差异。第一个示例将具有与迭代次数相同的变量数量。第二个示例只有一个变量。编译器足够聪明,在这里进行了一些优化,因此您不会注意到速度提高。 但是,如果您不想在再次离开循环后使用循环内生成的最后一个对象,则第一种解决方案更好。在第二个解决方案中,垃圾收集器需要一段时间才能释放最后创建的对象。在第一个示例中,垃圾收集器将更快地释放对象。它取决于其余的代码,但是如果您在此StringBuilder对象中存储了大量数据,则第二个示例可能会长时间保留此内存,从而降低代码离开循环后的性能!
另一方面,如果对象占用了100 KB,并且您的计算机有16 GB,那么没有人关心...垃圾收集器最终会再次释放它,可能是在包含此循环的方法离开时。


0
如果您有其他类似的代码段,您可以随时对其进行分析或在代码周围放置一些计时器,并运行基准测试以自行查看。另一个因素是内存占用量,其他人已经对此发表了评论。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接