17

我试图找出 Haskell 的线程(由forkIO产生的线程)究竟是如何映射到操作系统线程的。

我找到的第一个信息来源,

http://www.haskell.org/ghc/docs/latest/html/libraries/base/Control-Concurrent.html#g:11

指定所有轻量级线程实际上都在一个 OS 线程上运行,并且只有当 Haskell 线程使用安全 IO 操作阻塞时,GHC 运行时才会生成一个新的 OS 线程来运行其他 Haskell 线程,这样 IO 调用就不会阻塞整个程序。

第二个信息来源来自这里,

http://www.haskell.org/ghc/docs/7.0.1/html/users_guide/using-smp.html

它清楚地表明 Haskell 线程以平衡的方式映射到预定义数量的预先创建的 OS 线程。这或多或少意味着,如果我有 80 个轻量级线程,并且在运行程序时传递了选项 +RTS -N 8,那么将创建至少 8 个操作系统线程,每个这样的线程将运行 10 个轻量级线程。在具有 8 个 CPU 内核的机器上,这意味着大约 10 个 Haskell 线程/内核。

第二个信息来源似乎更准确,我希望 GHC 运行时在运行使用该-threaded标志编译的程序时会表现出这种确切的行为。

谁能证实这一点?而且,如果第二个版本是正确的,那么绑定线程的目的是什么 - 一个使用forkOS产生的线程 -是否仅用于处理使用线程本地数据的本机代码?

4

1 回答 1

24

-threaded不使用单个 OS 线程来运行所有 Haskell 线程的程序编译。外部调用将阻塞所有正在运行的 Haskell 线程。

编译的程序-threaded可以使用多个 OS 线程并行运行多个 Haskell 线程(OS 线程的数量可以通过+RTS -N选项控制)。标记的外部调用safe不会阻塞其他正在运行的 Haskell 线程(因此,-threaded即使+RTS -N1您有多个 Haskell 线程并发出可能需要很长时间的外部调用,使用它也可能是有益的)。标记的外部调用unsafe在 GHC 中实现为简单的内联函数调用,并将阻塞调用它们的 OS 线程。

关于您的第一个来源,它从单一功能的角度描述了发出外部呼叫时会发生什么。能力被定义为用于运行 Haskell 代码的虚拟 CPU,在线程化 RTS 中对应于 OS 线程的集合,任何时候只有一个线程在运行 Haskell 代码(其他 OS 线程用于在不阻塞 Haskell 的情况下进行外部调用线程)。当一个 Haskell 线程进行safe外部调用时,它会被放在挂起线程列表中,并且该功能被赋予不同的 Haskell 线程

绑定的Haskell线程有一个固定的关联 OS 线程,用于进行外部调用。未绑定线程没有关联的 OS 线程:来自该线程的外部调用可以在任何 OS 线程中进行。绑定线程用于与重要的库进行交互,对库的调用来自哪个 OS 线程,例如 OpenGL,它将其渲染上下文存储在 OS-thread-local-state 中。

更多信息可以在GHC 手册和以下论文中找到:

使用并发扩展 Haskell 外部函数接口

西蒙·马洛、西蒙·佩顿·琼斯和沃尔夫冈·塞勒,Haskell'04

于 2012-10-17T22:20:34.843 回答