Memory 加速Haskell并发

Memory 加速Haskell并发,memory,haskell,concurrency,lazy-evaluation,Memory,Haskell,Concurrency,Lazy Evaluation,MVar、TVar、IORef。。。我想我不能加速一个突如其来的问题 (我最初的问题是一个线程代码,我多次调用“addMany”来执行“forkIO”;但我认为我的问题在于“shW”函数) 让我们下一个代码: {-# LANGUAGE BangPatterns #-} import Control.Concurrent import Control.Monad import System.Environment(getArgs) import Data.Int import Data.IORef

MVar、TVar、IORef。。。我想我不能加速一个突如其来的问题

(我最初的问题是一个线程代码,我多次调用“addMany”来执行“forkIO”;但我认为我的问题在于“shW”函数)

让我们下一个代码:

{-# LANGUAGE BangPatterns #-}
import Control.Concurrent
import Control.Monad
import System.Environment(getArgs)
import Data.Int
import Data.IORef

-- "i" times, add "n" for each IORef (in "a")
addMany :: [IORef Int64] -> Int64 -> Int64 -> IO ()
addMany !a !n !i =
  forM_ [1..i] (\_ ->
    forM_ a (shW n))

-- MVar, TVar, IORef, ... read/write (x' = x + k)
shR = readIORef
shW !k !r = atomicModifyIORef r (\ !x' -> (x' + k, ()))

main = do
  (n':i':_) <- getArgs
  let (n, i) = (read n', read i')
  v <- forM [1..n] (\_ -> newIORef 0)
  addMany v 1 i
  mapM shR v >>= (putStrLn.show.sum)
我无法删除“shW”调用上的thunk(而且内存使用量很大)。怎么了

类似的C代码运行速度要快得多:

非常感谢

更新

在以下位置解决了原始问题:


非常感谢你不要Stewart

当您查看堆和GC时间时,很明显存在泄漏:

USDGHTVVH1$ time ./A 1000 10000 +RTS -s
10000000
   1,208,298,840 bytes allocated in the heap
   1,352,861,868 bytes copied during GC
     280,181,684 bytes maximum residency (9 sample(s))
       4,688,680 bytes maximum slop
             545 MB total memory in use (0 MB lost due to fragmentation)

                                    Tot time (elapsed)  Avg pause  Max pause
  Gen  0      1677 colls,     0 par    2.27s    2.22s     0.0013s    0.0063s
  Gen  1         9 colls,     0 par    1.66s    1.77s     0.1969s    1.0273s

  INIT    time    0.00s  (  0.00s elapsed)
  MUT     time    0.70s  (  0.77s elapsed)
  GC      time    3.92s  (  4.00s elapsed)
  EXIT    time    0.00s  (  0.00s elapsed)
  Total   time    4.62s  (  4.77s elapsed)

  %GC     time      84.8%  (83.8% elapsed)

  Alloc rate    1,718,469,461 bytes per MUT second

  Productivity  15.2% of total user, 14.7% of total elapsed

  real    0m4.752s
  user    0m0.015s
  sys     0m0.046s
2.8亿居民和89%总收入。许多恶棍正在被分配和丢弃

堆配置文件使这成为一种威胁

线索是这些是“stg_应用程序*”内容(即stg机器应用thunks)

modify函数族的一个微妙但引人注目的问题是这里的问题——当您有一个懒惰的atomicModify时,根本无法严格更新字段而不要求值。

因此,您对
原子修改ioref r(\!x'->(x'+k,())
的所有仔细使用就是构建
(+)
函数的应用程序链,这样就可以观察到链的结果(即单元格中的值),每个加法在其参数中都是严格的。不是你想要的!modifyIORef参数上的任何严格注释都不会对单元格本身产生任何影响。现在,通常情况下,您需要一个惰性修改——它只是一个指针交换,所以您可以有非常短的原子部分

但有时这不是你想要的

(关于这个问题的背景,请参见GHC ticket,然而,这个问题至少在2007年就已经知道了,当时我编写了这个包以避免MVAR出现这个问题。它是,我们现在在2012年有了严格的版本)

通过首先要求值,可以消除问题。例如

shW !k !r = --atomicModifyIORef r (\x -> (x + k, ()))
    do x <- shR r
       writeIORef r $! (x+1)
也就是说,22倍的加速,内存使用变得恒定。笑一下,这里是新的堆配置文件:


你在哪里分叉线程?为什么你认为这是一个thunk问题?Satvik,我将我的问题减少到只有一个线程如果我能解决它,我将尝试n个线程。谢谢J Fritsch,如果我调试(而不是配置文件),我会得到(我不确定,但我认为这是一个thunk问题)。谢谢“你可以使用atomicModifyIORef'来避免它”,是的,我读过但不明白(对不起,我的问题是MVar,TVar,…)。但现在一切都清楚了!非常感谢!
USDGHTVVH1$ time ./A 1000 10000 +RTS -s
10000000
   1,208,298,840 bytes allocated in the heap
   1,352,861,868 bytes copied during GC
     280,181,684 bytes maximum residency (9 sample(s))
       4,688,680 bytes maximum slop
             545 MB total memory in use (0 MB lost due to fragmentation)

                                    Tot time (elapsed)  Avg pause  Max pause
  Gen  0      1677 colls,     0 par    2.27s    2.22s     0.0013s    0.0063s
  Gen  1         9 colls,     0 par    1.66s    1.77s     0.1969s    1.0273s

  INIT    time    0.00s  (  0.00s elapsed)
  MUT     time    0.70s  (  0.77s elapsed)
  GC      time    3.92s  (  4.00s elapsed)
  EXIT    time    0.00s  (  0.00s elapsed)
  Total   time    4.62s  (  4.77s elapsed)

  %GC     time      84.8%  (83.8% elapsed)

  Alloc rate    1,718,469,461 bytes per MUT second

  Productivity  15.2% of total user, 14.7% of total elapsed

  real    0m4.752s
  user    0m0.015s
  sys     0m0.046s
shW !k !r = --atomicModifyIORef r (\x -> (x + k, ()))
    do x <- shR r
       writeIORef r $! (x+1)
USDGHTVVH1$ time ./A 1000 10000 +RTS -s
10000000
     120,738,836 bytes allocated in the heap
       3,758,476 bytes copied during GC
          73,020 bytes maximum residency (1 sample(s))
          16,348 bytes maximum slop
               1 MB total memory in use (0 MB lost due to fragmentation)

                                    Tot time (elapsed)  Avg pause  Max pause
  Gen  0       230 colls,     0 par    0.00s    0.01s     0.0000s    0.0001s
  Gen  1         1 colls,     0 par    0.00s    0.00s     0.0002s    0.0002s

  INIT    time    0.00s  (  0.00s elapsed)
  MUT     time    0.17s  (  0.17s elapsed)
  GC      time    0.00s  (  0.01s elapsed)
  EXIT    time    0.00s  (  0.00s elapsed)
  Total   time    0.19s  (  0.17s elapsed)

  %GC     time       0.0%  (3.9% elapsed)

  Alloc rate    643,940,458 bytes per MUT second

  Productivity 100.0% of total user, 108.3% of total elapsed


real    0m0.218s
user    0m0.000s
sys     0m0.015s