我有以下程序:
module Main where
import System (getArgs)
import Control.Concurrent
import Control.Monad
spawn left id = do
right <- newEmptyMVar
forkIO (thread id left right)
return right
thread id left right = go
where go = do l <- takeMVar left
putStrLn (show id)
putMVar right ()
main = do
args <- getArgs
if null args then
putStrLn "Arguments not supplied"
else do
initial <- newEmptyMVar
final <- foldM spawn initial [1..(read (head args))]
putMVar initial ()
takeMVar final
正如你所看到的,它只是创建了一堆线程:每个线程打印一个整数,但第二个线程在打印前等待第一个,第三个等待第二个,依此类推。我们不讨论这个程序的用处(这只是一个练习)。
现在,当我尝试创建一百万个线程时,该程序将被SIGKILL杀死。我想知道这个的原因。是因为MV太多了吗?
感谢。
答案 0 :(得分:2)
创建的每个线程都需要自己的程序堆栈。我实际上并不知道Haskell对其线程使用的堆栈有多大,但如果它是4kbytes(实际上非常小),那么对于百万个堆栈来说它将是4GB。如果你使用的是32位机器,那就是所有可寻址的内存,所以这显然不会起作用。典型的堆栈大小更像是兆字节!
答案 1 :(得分:2)
根据the GHC docs,每个线程的初始堆栈大小默认为1K,并且可以按需增长到每个线程8M。
您可以使用RTS选项-k
和-K
调整这些数字,例如:
$ ./Threads 1000000 +RTS -k512 -K1K -s
您的程序在我的系统上运行正常(64位,6GB RAM),但它的峰值消耗超过2GB。
4,743,629,168 bytes allocated in the heap
4,368,720,328 bytes copied during GC
1,043,256,808 bytes maximum residency (11 sample(s))
221,352,512 bytes maximum slop
2413 MB total memory in use (0 MB lost due to fragmentation)
Generation 0: 8707 collections, 0 parallel, 1.46s, 1.59s elapsed
Generation 1: 11 collections, 0 parallel, 1.72s, 3.16s elapsed
INIT time 0.00s ( 0.00s elapsed)
MUT time 5.86s ( 15.76s elapsed)
GC time 3.18s ( 4.75s elapsed)
EXIT time 0.08s ( 0.08s elapsed)
Total time 9.12s ( 20.59s elapsed)
%GC time 34.9% (23.1% elapsed)
Alloc rate 798,590,769 bytes per MUT second
Productivity 65.1% of total user, 28.9% of total elapsed
./Threads 1000000 +RTS -K1K -s 9.12s user 3.92s system 62% cpu 20.815 total