尝试创建多个线程时程序崩溃

时间:2011-05-09 10:53:52

标签: multithreading haskell concurrency

我有以下程序:

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太多了吗?

感谢。

2 个答案:

答案 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