sta*_*tti 3 haskell memory-leaks space-leak
考虑以下Haskell程序(我这样做主要是出于学习目的):
import qualified Control.Concurrent.MSem as Sem
import System.Environment (getArgs)
import Control.Concurrent (forkIO)
import Control.Monad
-- Traverse with maximum n threads
parallelTraverse :: Foldable a => Int -> (b -> IO()) -> a b -> IO ()
parallelTraverse n action values = do
sem <- Sem.new n
forM_ values $ \value -> Sem.with sem (forkIO $ action value)
main :: IO ()
main = do
args <- getArgs
let nThreads = read . head $ args :: Int
parallelTraverse nThreads print [(1::Int)..]
Run Code Online (Sandbox Code Playgroud)
当我运行它时,内存很快就会升至几GB.我尝试了各种组合以确保丢弃中间计算的结果(打印操作).为什么它还在泄漏空间?
首先,你在下面的一篇文章中有一个明显的错误:
Sem.with sem (forkIO $ action value)
Run Code Online (Sandbox Code Playgroud)
你正在围绕"fork"操作而不是那里的动作从主线程寻址信号量.以下是实施它的正确方法:
forkIO (Sem.with sem (action value))
Run Code Online (Sandbox Code Playgroud)
即,从分叉线程的上下文中解决信号量.
其次,在下面的代码中,您将parallelTraverse在无限列表上调用该操作:
parallelTraverse nThreads print [(1::Int)..]
Run Code Online (Sandbox Code Playgroud)
这导致线程无限分叉.而且由于forkIO调用线程的操作大致是即时的,因此很快你就会耗尽资源也就不足为奇了.
要使用信号量来限制工作线程的数量,with模式根本不会在您的情况下执行.相反,你应该使用和的明确组合,wait而signal不要忘记正确处理异常(如果你期望它们).例如,:
parallelTraverse :: Foldable a => Int -> (b -> IO()) -> a b -> IO ()
parallelTraverse n action values = do
sem <- Sem.new n
forM_ values $ \value -> do
Sem.wait sem
forkIO $ finally (action value) (Sem.signal sem)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
161 次 |
| 最近记录: |