不同的OS具有不同的并发子系统,Linux中有OS进程,POSIX线程以及当今的“ LWP”线程,Windows具有进程,光纤,线程等。每个进程都由OS调度程序进行调度,并拥有自己的CPU数量。时间。对于Linux“ LWP”来说,这是正确的,因为它们是进程,但共享内存空间,而对于用户空间线程,情况并非如此,因为所有线程共享一个CPU时间量。
Haskell具有forkIO。我在Haskell来源的下一篇评论中找到了
Haskell线程的调度是在Haskell内部完成的 运行时系统,并且不使用任何操作系统提供的 线程包。
也
就性能而言,“ forkOS”(又名绑定)线程更多 比“ forkIO”(又名未绑定)线程昂贵,因为“ forkOS” 线程绑定到特定的操作系统线程,而“ forkIO”线程 可以由任何OS线程运行。在“ forkOS”之间进行上下文切换 线程和“ forkIO”线程的价格比两者之间的价格高出许多倍 两个“ forkIO”线程。
强调了用forkIO
创建的线程不是由OS调度程序调度的。据我了解,它们可以不受常见限制(当然可以使用-thread
选项),但是在这种情况下,我有3个未解决的问题:
forkOS
比使用forkIO
更好吗?我的意思是,如果我有2个线程,其中一个服务于HTTP,而另一个则进行大量磁盘I / O操作,那么更好的解决方案是使用forkOS
而不是forkIO
? 答案 0 :(得分:2)
Haskell线程使用协作多线程。本质上,每次Haskell需要分配内存时,它都会检查是否经过了足够的时间,如果已过去,则会切换到下一个线程。确切的机制要复杂一些(我认为在某些时候它还涉及POSIX信号,例如“警报”),但这应该是主要思想。
运行时系统使N个Haskell线程在K个OS线程上运行。 K可由用户选择。然后由操作系统决定每个操作系统线程在哪个内核上运行-可能始终是同一内核。
IO繁重的操作应该不是大问题。 Haskell运行时使用无阻塞IO和轮询/选择来在所有线程上多路复用IO。另外,如果您有两个正在运行的Haskell线程,并且至少有两个OS线程专用于运行时,则这些线程应在OS线程上运行,OS应将这些线程分配给两个内核。随时尝试forkIO
与forkOS
进行比较,看看哪种可以为您的情况提供最佳性能,但是forkIO
在几乎所有情况下都应该更好。
答案 1 :(得分:0)
在具有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"
forkIO
和forkOS
都需要ghc-options: -threaded
选项才能利用多线程执行。在这两种情况下,我只能看到一个OS进程,但是看到多个线程。在forkIO
线程数为4的情况下,而在forkOS
线程数为3的情况下,更有趣的是上下文切换的数量,它与上述建议不同:在{{ 1}}(对于不同的线程):480000和48 ...,对于forkIO
,它们在同一时间段内分别约为2、3、16。这意味着forkOS
比forkIO
进行了更多的上下文切换(数十万vs数十),并且具有相同价值的汇总执行时间也应该更长,因此{{1} }在Windows上看起来更可取。
正如我在GHC源代码中看到的那样,POSIX线程在后台使用。
编辑。 Linux测试(forkOS
):
forkOS:
forkOS
forkIO:
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
情况下的Linux中,我们只有6个LWP,其中之一使用99%的CPU。在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
的情况下,我们有7个LWP,其中2个使用了约66%的CPU,从我的角度来看,这看起来更好。因此,似乎forkIO
在Linux中也更受欢迎。