如果我使用forkIO创建一个线程,我需要提供一个运行的函数并获取一个标识符(threadID)。然后,我可以通过例如与这种动物交流。工作负载,MVAR等。但是,根据我的理解,创建的线程非常有限,并且只能以SIMD方式工作,其中为线程创建提供的功能是指令。我无法更改线程启动时提供的功能。据我所知,这些用户线程最终是由操作系统映射到操作系统线程的。
我想知道Haskell线程和OS线程如何进行接口。为什么完全不同的Haskell线程可以映射到同一个OS线程?为什么不需要使用固定指令启动OS线程(因为forkIO需要)?调度程序(?)如何识别可能分发的应用程序中的用户线程?换句话说,为什么操作系统线程如此灵活?
最后,有没有办法从应用程序中转储所选线程的堆?
答案 0 :(得分:10)
首先,让我们解决一个快速误解:
据我所知,这些用户线程最终是由OS映射到操作系统线程的。
实际上,Haskell运行时负责选择从其池中执行的特定OS线程正在执行哪个Haskell线程。
现在问题,一次一个。
为什么完全不同的Haskell线程可以映射到同一个OS线程?
暂时忽略FFI,所有操作系统线程实际上都在运行Haskell运行时,它跟踪已准备好的Haskell线程列表。运行时选择一个Haskell线程来执行,并跳转到代码中,执行直到线程将控制权交还给运行时。此时,运行时有机会继续执行相同的线程或选择不同的线程。
简而言之:许多Haskell线程可以映射到单个OS线程,因为实际上OS线程只做一件事,即运行Haskell运行时。
为什么不需要使用固定指令启动OS线程(因为forkIO需要它)?
我不明白这个问题(我认为这源于第二个误解)。您使用固定指令启动操作系统线程的方式与使用固定指令启动Haskell线程的方式完全相同:对于每个操作,您只需要执行一大块代码即可。这就是它的作用。
调度程序(?)如何识别可能分发的应用程序中的用户线程?
“分布式”是一个危险的词:通常,它指的是在多台机器上传播代码(大概不是你在这里所说的)。至于Haskell运行时如何判断何时存在多个线程,那很容易:当你调用forkIO
时告诉它。
换句话说,为什么操作系统线程如此灵活?
我不清楚OS线程比Haskell线程更灵活,所以这个问题有点奇怪。
最后,有没有办法从应用程序中转储所选线程的堆?
实际上我根本不知道任何用于转储Haskell堆的工具,多线程应用程序或其他工具。如果愿意,可以使用像vacuum这样的包转储从特定对象可到达的堆部分的表示。我曾使用vacuum-cairo来显示这些转储,并在过去取得了巨大的成功。
有关详细信息,您可以从我的intro to multithreaded gtk2hs programming中享受中间两个部分,“约定”和“外国进口”,也可能还有“非线程运行时”部分的内容。
答案 1 :(得分:8)
我将尝试提供一个关于如何实现多线程Haskell程序的概念模型,而不是试图直接回答您的问题。我会忽略许多细节和复杂性。
操作系统使用preemptive multithreading实现hardware interrupts,以允许多个“线程”计算同时在同一核心上逻辑运行。
操作系统提供的线程往往很重。它们非常适合某些类型的“多线程”应用程序,并且在Linux等系统上,基本上是允许多个程序同时运行的工具(他们擅长的任务)。
但是,这些线程对于Haskell等高级语言中的许多用途来说有点沉重。从本质上讲,GHC运行时作为迷你操作系统,在操作系统线程之上实现自己的“线程”,就像操作系统在核心上实现线程一样。
概念上很容易想象像Haskell这样的语言会以这种方式实现。评估Haskell包括“强制thunk”,其中thunk是一个计算单位,可能依赖于另一个值(thunk)和/或2.创建新的thunk。
因此,可以想象多个线程同时评估thunks。一个人将构建一个待评估的thunks队列。每个线程都会弹出队列的顶部,并评估该thunk直到它完成,然后从队列中选择一个新的thunk。操作par
及其同类可以通过向该队列添加thunk来“激发”新计算。
将此模型扩展到IO操作也不是特别难以想象。我们想象Haskell计算的单位有点复杂,而不是简单地强制纯粹的thunk。 Psuedo Haskell用于这样的运行时:
type Spark = (ThreadId,Action)
data Action = Compute Thunk | Perform IOAction
注意:这仅用于概念性理解,不要认为事情是以这种方式实现的
当我们运行Spark时,我们会查找“抛出”到该线程ID的异常。假设我们没有,执行包括强制thunk或执行IO操作。
显然,我在这里的解释是非常手工的,并忽略了一些复杂性。更多的是,GHC团队撰写了很多文章,如Marlow等人的“Runore Support for Multicore Haskell”。您可能还想查看操作系统上的教科书,因为它们经常深入探讨如何构建调度程序。