2010-01-09 38 views
3

我想为我的个人项目开发一些异步方法,并且正在研究框架以供参考。将对象字段分配给局部变量有什么优势?

我已经下载了.NET source code来看一看位和螺栓更紧密地(与开发商的意见,一些反射并没有给我们:-P)

不管怎样,在很多.NET的班我遇到了以下模式:

class SomeType 
{ 
    // ... 
    SomeClass m_Field; 
    // ... 
    SomeClass SomeMethod() 
    { 
    SomeClass localField = m_Field; 
    if (localField == null) 
    { 
     localField = new SomeClass(); 
     m_Field = localField; 
    } 
    return localField; 
    } 
} 

这让我想知道使用这种模式的优点是什么?

据我所知,上面的图案更糟糕的是,在性能方面,除了下面的一个:

class SomeType 
{ 
    // ... 
    SomeClass m_Field; 
    // ... 
    SomeClass SomeMethod() 
    { 
    if (m_Field == null) 
    { 
     m_Field = new SomeClass(); 
    } 
    return m_Field; 
    } 
} 

还是我失去了一些东西?

+1

你能举一个具体的例子吗?你看过SomeClass的什么类型?它是某种类型的集合吗? – 2010-01-09 23:12:49

回答

2

在许多情况下,所不同的是纯粹的审美和主观的,但三个原因考虑一个与其他浮现在脑海中:

  1. 线程安全:无锁算法可能需要担心这个,但是如果所有的同步都是通过锁来完成的话,那应该不是问题。

  2. 性能:可能稍微快一点在某些情况下,但老实说,我怀疑它会在大多数情况下的差异。

  3. 异常安全性:通常您需要小心把中间变为当地人,并只有在操作已经没有引发异常完成结果发布到各个领域。这充当事务处理机制,因为没有人会看到只有一半字段设置的对象。

+1

堆栈溢出只是挑战我,我可能不是人。我是新来的,今天很开心。 – 2010-01-09 23:30:26

+0

难道你不喜欢他们展示的机器人西装男生的照片! – 2010-01-09 23:40:32

0

这可能只是暗示编译器应该将字段读入寄存器而不是在内存中反复访问它。没有什么理由说明为什么第一个版本应该是更差性能明显比你列出的第二个版本。它几乎是编译器生成的相同代码。将对象字段读入寄存器,测试它是否为空,根据需要对其进行修改,然后将其写回内存中的对象字段。

2

当您从一个线程调用SomeMethod时,此类方法可能有助于保护您,但在您检查m_Field为null后,控制权将传递给另一个将其设置为null的线程。然后控制返回到第一个线程,但它仍然认为m_Field!= null,这可能会导致NullReferenceException

据我记得在Richter的“CLR via C#”中有几个关于它的字眼事件。

0

MS .NET JIT确实register allocation。对于这样一个简单的情况,该临时变量最终应该保存在寄存器中,而不是堆栈中。生成的x86字节代码的运行速度应该比类成员读取两次(一次检查为空,一次返回)非空的情况更快,并且空的情况也更快。

代码生成器必须尽快,因为它们发生在对象一般写入修改字段,从对象字段每次被引用时读取,否则在某些情况下,一个线程可能会从未看变化由另一个线程创建的对象,反之亦然。

但如果使用本地变量编译器假定它没有写入到本地变量的变化(甚至把它存储在堆栈),因为访问另一个线程的当地人是不是东西,C#允许。

相关问题