我不会尝试直接回答您的问题,而是尝试为如何实现多线程 Haskell 程序提供一个概念模型。我将忽略许多细节和复杂性。
操作系统使用硬件中断实现抢占式多线程,以允许多个计算“线程”同时在同一内核上逻辑运行。
操作系统提供的线程往往很重。它们非常适合某些类型的“多线程”应用程序,并且在 Linux 等系统上,它们基本上是允许多个程序同时运行的相同工具(它们擅长的任务)。
但是,这些线程对于 Haskell 等高级语言的许多用途来说有点重。本质上,GHC 运行时就像迷你操作系统一样工作,在操作系统线程之上实现自己的“线程”,就像操作系统在内核之上实现线程一样。
从概念上很容易想象像 Haskell 这样的语言会以这种方式实现。评估 Haskell 包括“强制 thunk”,其中 thunk 是一个计算单元,它可能 1. 依赖于另一个值(thunk)和/或 2. 创建新的 thunk。
因此,可以想象多个线程同时评估 thunk。一个人会构建一个待评估的 thunk 队列。每个线程将弹出队列的顶部,并评估该 thunk 直到它完成,然后从队列中选择一个新的 thunk。该操作par
及其同类可以通过向该队列添加一个 thunk 来“激发”新的计算。
将此模型扩展到 IO 操作也不是特别难想象。不是每个简单地强制纯 thunk,我们想象 Haskell 计算的单元会更复杂一些。Psuedo Haskell 用于这样的运行时:
type Spark = (ThreadId,Action)
data Action = Compute Thunk | Perform IOAction
注意:这仅用于概念理解,不要认为事情是这样实现的
当我们运行 Spark 时,我们会寻找“抛出”到该线程 ID 的异常。假设我们没有,执行包括强制 thunk 或执行 IO 操作。
显然,我在这里的解释非常随意,忽略了一些复杂性。此外,GHC 团队还撰写了 Marlow 等人的“Runtime Support for Multicore Haskell”等优秀文章。您可能还想查看有关操作系统的教科书,因为它们经常深入探讨如何构建调度程序。