Haskell的forkIO的实现

Pau*_*-AG 5 concurrency haskell

不同的操作系统有不同的并发子系统,有操作系统进程、POSIX 线程,现在 Linux 中还有“LWP”线程,Windows 有进程、纤程、线程等。每个进程都由操作系统调度程序进行调度,并获得自己的 CPU 时间量。对于 Linux“LWP”来说确实如此,因为它们是进程但共享内存空间,而对于用户空间线程则不然,其中所有线程共享一个 CPU 时间量。

Haskell 有 forkIO。我在 Haskell 源代码中找到了下一个评论:

Haskell 线程的调度是在 Haskell 运行时系统内部完成的,并且不使用任何操作系统提供的线程包。

在性能方面,“forkOS”(又名绑定)线程比“forkIO”(又名未绑定)线程昂贵得多,因为“forkOS”线程绑定到特定操作系统线程,而“forkIO”线程可以运行由任何操作系统线程。“forkOS”线程和“forkIO”线程之间的上下文切换比两个“forkIO”线程之间的上下文切换要昂贵很多倍。

它强调创建的线程forkIO不是由操作系统调度程序调度的。据我了解,它们可以免受常见阻塞(当然可以-thread选择),但在这种情况下,我有 3 个悬而未决的问题:

  1. 它们(用 forkIO 创建的“线程”)如何共享这些 CPU 量子?
  2. 它们是否能保证分布到不同的核心,或者因为它们由一个进程表示,所以不会?或者这是非确定性行为?
  3. 我认为避免干扰效果forkOS比使用更好,对吗forkIO?我的意思是,如果我有 2 个线程,其中一个线程提供 HTTP 服务,另一个线程进行大量磁盘 I/O 操作,那么更好的解决方案是使用forkOSforkIO?

Pau*_*-AG -1

在具有 4 核 CPU 的 Windows 10 上进行的少量测试显示结果:

module Main where

import Control.Monad
import Control.Concurrent

t1 = forever $ print "1"
t2 = forever $ print "2"

main :: IO ()
main = do
  t1id <- forkOS t1 -- I tried forkOS and forkIO
  t2id <- forkOS t2
  getLine
  putStrLn "Done"
Run Code Online (Sandbox Code Playgroud)

两者forkIOforkOS需要ghc-options: -threaded选择使用多线程执行。在这两种情况下,我只看到一个操作系统进程,但看到多个线程。在线程数的情况下forkIO是 4,而在情况下forkOS我只得到 3。更有趣的是上下文切换的数量,它与提到的建议不同:在forkIO它们的情况下(对于不同的线程):480000 和 48。 .. 在forkOS同一时间段内,它们大约为 2、3、16。这意味着forkIO进行更多的上下文切换forkOS数十万 vs 数十),并且相同有价值效果的总执行时间应该更大,因此forkOS在 Windows 机器上看起来更可取。

正如我在 GHC 源代码中看到的,POSIX 线程正在幕后使用。

编辑。Linux测试(ps -eLf):

分叉操作系统:

UID        PID  PPID   LWP  C NLWP STIME TTY          TIME CMD
...        ...   ...   ... ... ...   ... ...           ... ...
xyz     7432  4865  7432  0    7 10:03 pts/0    00:00:00 /home/xyz/prj/thr/.stack-work/install/x86_64-linux-tinfo6/lts-13.25/8.6.5/bin/yohoho
xyz     7432  4865  7448  0    7 10:03 pts/0    00:00:00 /home/xyz/prj/thr/.stack-work/install/x86_64-linux-tinfo6/lts-13.25/8.6.5/bin/yohoho
xyz     7432  4865  7449  0    7 10:03 pts/0    00:00:00 /home/xyz/prj/thr/.stack-work/install/x86_64-linux-tinfo6/lts-13.25/8.6.5/bin/yohoho
xyz     7432  4865  7450  0    7 10:03 pts/0    00:00:00 /home/xyz/prj/thr/.stack-work/install/x86_64-linux-tinfo6/lts-13.25/8.6.5/bin/yohoho
xyz     7432  4865  7451 66    7 10:03 pts/0    00:00:06 /home/xyz/prj/thr/.stack-work/install/x86_64-linux-tinfo6/lts-13.25/8.6.5/bin/yohoho
xyz     7432  4865  7452  0    7 10:03 pts/0    00:00:00 /home/xyz/prj/thr/.stack-work/install/x86_64-linux-tinfo6/lts-13.25/8.6.5/bin/yohoho
xyz     7432  4865  7453 67    7 10:03 pts/0    00:00:06 /home/xyz/prj/thr/.stack-work/install/x86_64-linux-tinfo6/lts-13.25/8.6.5/bin/yohoho
Run Code Online (Sandbox Code Playgroud)

分叉IO:

UID        PID  PPID   LWP  C NLWP STIME TTY          TIME CMD
...        ...   ...   ... ... ...   ... ...           ... ...
xyz     8209  4865  8209  0    6 10:08 pts/0    00:00:00 /home/xyz/prj/thr/.stack-work/install/x86_64-linux-tinfo6/lts-13.25/8.6.5/bin/yohoho
xyz     8209  4865  8225  0    6 10:08 pts/0    00:00:00 /home/xyz/prj/thr/.stack-work/install/x86_64-linux-tinfo6/lts-13.25/8.6.5/bin/yohoho
xyz     8209  4865  8226  0    6 10:08 pts/0    00:00:00 /home/xyz/prj/thr/.stack-work/install/x86_64-linux-tinfo6/lts-13.25/8.6.5/bin/yohoho
xyz     8209  4865  8227  0    6 10:08 pts/0    00:00:00 /home/xyz/prj/thr/.stack-work/install/x86_64-linux-tinfo6/lts-13.25/8.6.5/bin/yohoho
xyz     8209  4865  8228 99    6 10:08 pts/0    00:00:06 /home/xyz/prj/thr/.stack-work/install/x86_64-linux-tinfo6/lts-13.25/8.6.5/bin/yohoho
xyz     8209  4865  8229  0    6 10:08 pts/0    00:00:00 /home/xyz/prj/thr/.stack-work/install/x86_64-linux-tinfo6/lts-13.25/8.6.5/bin/yohoho
Run Code Online (Sandbox Code Playgroud)

在 Linux 中,forkIO我们只有 6 个 LWP,其中一个的 CPU 利用率达到 99%。在我们有 7 个 LWP 的情况下forkOS,其中 2 个 LWP 的 CPU 利用率约为 66%,在我看来,这看起来更好。所以,似乎这forkOS在 Linux 中也更可取。