【问题标题】:Variable scope and performance可变范围和性能
【发布时间】:2010-07-02 08:53:17
【问题描述】:

下面是我正在使用的代码

private void TestFunction()
{
  foreach (MySampleClass c in dictSampleClass)
  {
    String sText = c.VAR1 + c.VAR2 + c.VAR3
    PerformSomeTask(sText,c.VAR4);
  }
}

我的朋友建议更改为(以提高性能。dictSampleClass 是一个字典。它有 10K 个对象)

private void TestFunction()
{
  String sText="";
  foreach (MySampleClass c in dictSampleClass)
  {
    sText = c.VAR1 + c.VAR2 + c.VAR3
    PerformSomeTask(sText,c.VAR4);
  }
}

我的问题是,“上述更改是否会提高性能?如果是,如何?”

哇,这超出了预期的响应。大多数人说“C# 编译器会处理这个问题”。那么c编译器呢??

【问题讨论】:

  • 如果这能提高性能,我会感到非常惊讶。但这会损害可读性。
  • 有一个(可忽略不计的)性能 HIT,因为您分配空字符串只是为了立即在 foreach 内重新分配。
  • 您可以避免将 sText 设置为空,因为它在每次迭代时都会被初始化。正如其他人所说,编译器将生成相同的代码,但我发现在循环外声明变量更简洁。也就是说,请注意以这种方式连接 3 个字符串,产生的字符串比预期的多 2 个(tmp1=c.Var1+c.Var2 和 tmp2=tmp1+c.Var3),所以它可能是值得的(为了尽可能少地使用内存根据需要)使用一个大小预先初始化为 (c.VAR1.Length+c.VAR2.Length+c.VAR3.Length) 的 StringBuilder。
  • 您可以自己回答这个问题。 两种方法都试一下,看看性能是否不同。如果你不能区分,那么性能没有不同。更好的性能的全部意义在于它明显更好。

标签: c#


【解决方案1】:

编译器可以根据需要将变量声明移入/移出循环。但是,在您的示例中,您使用的是不可变的字符串。通过在外部声明它,我相信您正在尝试“创建一次,使用多次”,但是每次修改字符串时都会创建字符串,因此您无法实现。

听起来并不粗俗,但这是一个过早的优化,而且很可能是一个失败的优化 - 由于字符串的不变性。

如果集合很大,请沿着将许多字符串附加到 StringBuilder 的路线 - 用分隔符分隔。然后在此分隔符上拆分字符串并迭代数组以添加它们,而不是连接它们并在一个循环中添加它们。

StringBuilder sb = new StringBuilder();

foreach (MySampleClass c in dictSampleClass)
{
    sb.Append(c.VAR1);
    sb.Append(c.VAR2);
    sb.Append(c.VAR3);
    sb.Append("|");
}

string[] results = sb.ToString().Split('|');

for (int i = 0; i < dictSampleClass.Count; i++)
{
    string s = results[i];
    MySampleClass c = dictSampleClass[i];
    PerformSomeTask(s,c.VAR4); 
}

我推断使用此代码没有任何好处 - 很可能甚至不起作用!

更新:鉴于从多个字符串创建字符串的快速性能,如果 PerformSomeTask 是您的瓶颈,请尝试将字符串的迭代分解为多个线程 - 这不会提高效率的代码,但您将能够利用多个内核。

【讨论】:

  • 同上现在意识到从多个字符串初始化一个字符串非常快。
【解决方案2】:

通过反射器运行这两个函数,看看生成的程序集。它可能会提供一些见解,但充其量,性能提升将是最小的。

【讨论】:

    【解决方案3】:

    我会这样做:

    private void TestFunction() 
    { 
      foreach (MySampleClass c in dictSampleClass) 
      { 
        PerformSomeTask(c.VAR1 + c.VAR2 + c.VAR3, c.VAR4); 
      } 
    } 
    

    可能仍然没有真正的性能优势,但它消除了创建您并不真正需要的变量。

    【讨论】:

    • Hmmmm.. 我的目标只是知道差异而不是代码优化。
    【解决方案4】:

    不,它没有。诸如此类的事情由 C# 编译器处理,它非常智能,您基本上不需要关心这些细节。

    总是使用提高可读性的代码。

    你可以通过反汇编程序来检查。

    【讨论】:

      【解决方案5】:

      Ii 不会提高性能。但另一方面:假设的改进很容易出错。您必须测量您的应用程序,并且仅在需要时优化慢速部分。我不认为循环是您的应用程序的瓶颈。

      【讨论】:

      • 也不安全地假设,10k 个字符串连接在紧密循环中的项目 - 可能会占用内存。
      • @Adam:这并不是真正的循环中的字符串连接,而是来自多个来源的字符串初始化。它与String str = c.VAR1; str += c.VAR2; str += c.VAR3 不同,会导致性能问题。
      • @ck 是的,我从来没有考虑过它的性能差异。
      猜你喜欢
      • 2014-11-22
      • 2014-04-05
      • 2021-11-13
      • 1970-01-01
      • 2016-01-09
      • 2018-09-19
      • 2016-09-14
      • 2011-07-28
      • 1970-01-01
      相关资源
      最近更新 更多