我的理解是GHC为每个线程提供堆栈。为什么这有必要? GHC不编译到CPS吗?这个线程不是简洁地表达为闭包吗?
答案 0 :(得分:5)
您的问题有几个方面。
GHC运行时中设计决策的关键参考是论文''Runtime Support for Multicore Haskell''。
回想一下
GHC运行时系统支持数百万个轻量级线程 通过将它们复用到少数操作系统线程上, 每个物理CPU大约只有一个。
和
每个Haskell线程在一个有限大小的堆栈上运行,该堆栈被分配 堆。线程的状态及其堆栈保存在a中 堆分配的线程状态对象(TSO)。 TSO的大小就在附近 15个字加上堆栈,构成了Haskell的整个状态 线。通过将TSO复制到更大的区域,可以增加堆栈 随后可能会再次缩小
GHC不通过CPS编译。每个线程都进行递归调用,并且它们必须分配给堆栈。通过将堆栈表示为堆分配的对象,事情变得更简单。
一个线程不仅仅是一个闭包。
当一个线程执行时,它开始分配给堆和堆栈。因此:
线程的堆栈,因此它的TSO是可变的。当一个 线程执行,堆栈将累积指向新对象的指针, 因此,如果TSO位于旧一代,则必须将其添加到 记得的[GC]集。
可以优化堆栈指向的垃圾收集对象,以确保GC与线程在同一物理线程上进行。
此外,当垃圾收集器运行时, 非常希望已经执行的TSO 给定的CPU由同一CPU上的垃圾收集器遍历, 因为它所引用的TSO和数据很可能在本地 该CPU的缓存。
因此,GHC为每个线程都有一个堆栈,因为编译要求线程可以访问堆栈和堆。通过为每个线程提供自己的堆栈,线程可以更有效地并行执行。线程不只是“只是一个闭包”,因为它们有一个可变的堆栈。