gpt4 book ai didi

haskell - 为什么我的并行遍历 Haskell 程序会泄漏内存?

转载 作者:行者123 更新时间:2023-12-02 21:18:55 26 4
gpt4 key购买 nike

考虑以下 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)..]

当我运行它时,内存迅速攀升至几 GB。我尝试了各种组合以确保丢弃中间计算的结果(打印操作)。为什么仍然泄漏空间?

最佳答案

首先,您在以下文章中有一个明显的错误:

Sem.with sem (forkIO $ action value)

您正在围绕“fork”操作而不是那里的操作从主线程寻址信号量。以下是实现它的正确方法:

forkIO (Sem.with sem (action value))

即,从 fork 线程的上下文中寻址信号量。

其次,在以下代码中,您将在无限列表上调用 parallelTraverse 操作:

parallelTraverse nThreads print [(1::Int)..]

这会导致线程的无限 fork 。由于 forkIO 操作对于调用线程来说大致是瞬时的,因此您很快就会耗尽资源也就不足为奇了。

<小时/>

要使用信号量来限制工作线程的数量,with 模式在您的情况下根本行不通。相反,您应该使用 waitsignal 的显式组合,并且不要忘记正确处理异常(如果您期望它们)。例如:

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)

关于haskell - 为什么我的并行遍历 Haskell 程序会泄漏内存?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32445309/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com