我对.NET和CPU缓存有一点误解。我认为只有线程堆栈存储在CPU缓存中,但显然是堆的一部分,具体是Gen 0 is actually allocated in the CPU L2 cache。
我读过几件事:The initial size limit of Gen 0 is determined by the size of the processor cache.
但是当Gen 0大于处理器缓存的大小时会发生什么?然后在RAM和缓存之间分开?怎么样?否则完全转移到RAM?我读过有人声称他们的Gen 0大约为500 Mb的评论,所以他们不太可能拥有500Mb的CPU缓存。
据我所知(我可能知道错误),Gen 0中的对象可以跨线程共享,那么如果存储在CPU缓存中,如何在不同CPU中调度的线程之间共享对象?如果.NET不是本地的,那么.NET是否关心将对象放入RAM中?
答案 0 :(得分:3)
你对CPU缓存(实际上是CPU本身以及它上面的整个抽象层)如何工作有很大的误解。 .NET不能强制任何CPU缓存,这完全是CPU和其他任何人的责任。缓存始终是RAM的副本,如果它在缓存中(并且它仍然有效),它也将在RAM中。无论如何,所有这些都是一个实现细节,无论如何你都不能依赖它。
您的所有问题都需要相当广泛的答案。简单的答案是多线程编程非常困难,如果你不这么认为,你真的没有太多的经验:)一旦你意识到CPU的大量假设和性能优化,你'我还会意识到C ++与C#的关系并不像“真正的硬件”那么接近。
默认情况下,所有内存都在线程间共享 - 如果您传递了引用。这是坏,因为它会引起同步问题。有些是由缓存引起的(无论是在CPU缓存中还是在CPU寄存器中),有些是由于您执行的大多数操作都不是原子操作引起的。
现在,当然,如果你正在进行一些独立的,受CPU限制的工作,你可以从使用你正在使用的整个内存到CPU缓存中获得很多好处。你只能通过使用足够小的数据结构来帮助它 - 你不能强制缓存一些信息或任何东西(实际上,你从内存中读取的每一件事都将在CPU中缓存在某一点 - CPU 不能直接从RAM读取 - RAM太慢了。如果您可以将整个数据放入缓存中,并且没有人会让您从缓存中逐出(请记住,多任务环境),即使从传统上昂贵的操作中获得惊人的性能(例如,在内存中大量跳转而不是顺序访问等。)。
但是,一旦你需要在线程之间共享数据,你就会开始遇到麻烦。您需要同步以确保两个CPU(或CPU核心,我不打算区分它们)实际上正在处理相同的数据!
现在,在实践中,您将发现CPU缓存往往在核心之间共享。这很好,因为共享CPU缓存仍然比通过RAM进行同步快一个数量级。但是,你仍然可以遇到许多问题,例如非常有趣的案例,比如这个非常典型的线程循环:
while (!aborted)
{
...
}
理论上,这很可能恰好是一个无限循环。积极的编译器可能会发现您永远不会更改aborted
的值,只需将!aborted
替换为true
(.NET不会),或者它可能存储{{1}的值1}}在寄存器中。
默认情况下,寄存器不会自动同步。如果线程循环的主体足够简单,这可能是一个非常大的问题。当您深入研究多线程编程时,您将完全被您以前编写的代码和您曾经拥有的假设所破坏。
最重要的是要记住,编译器和CPU所做的所有优化只能保证在你将它们隔离并在单个线程中运行时不会改变行为。当你打破这个假设时,一切都会崩溃。