2016-04-29 103 views
0

我前几天和一位同事讨论了这个假设情况。运行编译代码时C# - 变量范围和处理如何影响处理效率?

public void Main() 
{ 
    string1 = null; 
    string2 = null, 
    MyDto dto = Repository.GetDto(); 

    foreach(var row in dto.Rows) 
    { 
     ProcessStrings(row, string1, string2) 
    } 
} 

public void ProcessStrings(DataRow row, string string1, string string2) 
{ 
    string1 = GetStringFromDataRow(row, 1); 
    string2 = GetStringFromDataRow(row, 2); 

    // do something with the strings 
} 

如何将这些在处理不同:考虑这个伪代码:

public void Main() 
{ 
    MyDto dto = Repository.GetDto(); 

    foreach(var row in dto.Rows) 
    { 
     ProcessStrings(row); 
    } 
} 

public void ProcessStrings(DataRow row) 
{ 
    string string1 = GetStringFromDataRow(row, 1); 
    string string2 = GetStringFromDataRow(row, 2); 

    // do something with the strings 
} 

那么这个功能相同的选择吗?我们是否认为第二个版本的效率更高一些,因为字符串变量会占用较少的内存并且只能被放置一次,而在第一个版本中,它们在循环的每一遍都会被处理掉?

如果第二个版本中的字符串被refout参数传递,会有什么区别吗?

+1

他们没有被处置。他们正在GC'd。 – Karolis

+0

我期望第二个版本稍微慢一点*,因为你传递的是不必要的参数。您正在交易参数的局部变量,但两者都只是对实际字符串对象的引用。 –

+1

@PieterWitvoet在CPU级这两个例子可以处理使用CPU寄存器和/或叠层,其可能或可能不实际具有相同的执行配置文件的变量和参数。换句话说,即使C#代码不同,在最终代码中可能根本就没有任何区别。然而,有些代码很可能会被移动,但是我怀疑这是否会在高度理论层面上起作用。 –

回答

2

当您处理“稍微更高效”的优化级别时,您可能无法看到整个图景并最终导致“边际效率较低”。

这里这个答案的风险同样的事情,但与告诫,让我们来看看假设:

存储字符串转换成变量创建字符串的新实例

一点都不。一个字符串是一个对象,你在变量中存储的是对该对象的引用。在32位系统上,这个引用的大小是4个字节,在64位上是8个。没有更多,没有更多。移动4/8字节是开销,你不会注意到很多。

所以既不的两个例子,我们所拥有的有关方法气质的信息很少被调用,创建等等这算他们相当于比其他更多或更少的字符串。

那么有什么不同呢?

那么在一个例子中,你正在将两个字符串引用存储到局部变量中。这很可能是cpu寄存器。可能是堆栈中的内存。很难说,取决于其余的代码。有关系吗?不大可能。

在其他例子中,你正在传递两个参数为null,然后在本地重新使用这些参数。这些参数可以作为cpu寄存器或堆栈存储器传递。和其他一样。它有关系吗?一点也不。

所以最有可能是完全没有任何区别。

注意一件事,你提的“处置”。该术语保留用于实现IDisposable的对象,然后通过在这些对象上调用IDisposable.Dispose来处置这些对象。字符串不是这样的对象,这与这个问题无关。

如果您的意思是“垃圾收集”,那么既然我已经确定这两个示例都不会因为您提出的差异而创建比其他对象多或少的对象,这也是无关紧要的。

这并不重要,但是。这是不重要的,你或我或你的同事认为将会产生影响。不知道是完全不同的,这使我...

真正的尖端我可以给有关优化:

  1. 措施
  2. 措施
  3. 措施
  4. 理解
  5. 确认您理解正确
  6. 变化,如果可能的话

你测量,使用一个分析器找到真正的瓶颈和实时挥金如土在你的代码,然后明白,为什么那些瓶颈,然后确保您的理解是正确的,那么你可以看到,如果你可以改变它。

在你的代码,我会大胆猜测,如果你来分析你的程序,你会发现,这两个例子绝对没有对运行时间任何效果。如果他们有效果它将在纳秒级。最有可能的是,查看分析器结果的行为会给你一个或多个关于你的程序的“呃,这很奇怪”的实现,你会发现比这里的变量更大的瓶颈。

+0

谢谢。我们测量的东西,并意识到这种差异的影响可能会忽略不计。这只是一个好奇心问题,并且希望了解编译代码如何最终被处理器解释。 –

+1

在这个详细程度上,我会编写代码给你最温暖的模糊,并让编译器实际的细节。换句话说,例如#1。 –

2

在这两种替代方法中,GetStringFromDataRow每次都会创建一个新字符串。无论您将参考存储到本地变量中的参数字符串还是参数变量参数(与您的案例中的本地变量本质上没有太大差别)都无关紧要。想象你甚至没有将结果GetStringFromDataRow分配给任何变量 - 字符串实例仍然被创建并存储在内存中的某个地方,直到垃圾收集。如果你通过引用传递你的字符串 - 它不会有太大的区别。您将能够重新使用内存位置来将参考存储到创建的字符串(您可以将其视为字符串实例的内存地址),但不能将字符串内容存储到位置。