我试图找出Haskell的线程(由forkIO生成的线程)到底是如何映射到OS线程的。
我找到的第一个信息来源,
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个OS线程,并且每个这样的线程将运行10个轻量级线程。在具有8个CPU核心的计算机上,这意味着大约10个Haskell线程/核心。
第二个信息来源似乎是更准确的信息,我希望GHC运行时在运行使用-threaded
标志编译的程序时能够显示这种行为。
任何人都可以证实吗?而且,如果第二个版本是正确的,绑定线程的目的是什么 - 一个使用forkOS生成的 - 它是否仅用于处理使用线程本地数据的本机代码?
答案 0 :(得分:23)
在没有-threaded
的情况下编译的程序使用单个OS线程来运行所有Haskell线程。外部调用将阻止所有正在运行的Haskell线程。
使用-threaded
编译的程序可以使用多个OS线程并行运行多个Haskell线程(可以通过+RTS -N
选项控制OS线程的数量)。标记为safe
的外部调用不会阻止其他正在运行的Haskell线程(因此,如果您有多个Haskell线程并发出可能需要的外部调用,那么即使使用-threaded
也可能有用+RTS -N1
很长时间)。标记为unsafe
的外部调用在GHC中实现为简单的内联函数调用,并将阻止调用它们的OS线程。
关于您的第一个来源,它描述了从单个功能的角度发出外来呼叫时会发生什么。 capability被定义为用于运行Haskell代码的虚拟CPU,并且在线程RTS中对应于OS线程的集合,其中只有一个在任何时候运行Haskell代码(其他OS线程用于制作外部代码)调用而不阻塞Haskell线程)。当Haskell线程进行safe
外来呼叫时,it is put on the list of suspended threads and the capability is given to a different Haskell thread。
绑定 Haskell线程具有固定的关联OS线程,用于进行外部调用。 未绑定线程没有关联的OS线程:来自此线程的外部调用可以在任何OS线程中进行。绑定线程用于与库进行交互,对于这些库来说,对哪个OS调用是从哪个操作系统线程(如OpenGL)进行交互,后者将其渲染上下文存储在OS-thread-local-state中。
更多信息可在GHC manual和以下文件中找到:
Extending the Haskell Foreign Function Interface with Concurrency
Simon Marlow,Simon Peyton Jones和Wolfgang Thaller,Haskell'04