3

runResourceT単一の有効期間をスコープする方法はありSinkますか?

Sink潜在的に無限の数をラップするを構築しようとしていますSinks。これはスレッドで問題なく動作しますが、スレッドなしで実行しようとしています。それは可能であるように思われます。のスコーピングが原因で障害にぶつかりましたrunResourceT: リソース管理が粗すぎる (ただし機能的) か、きめが細かすぎる (完全に壊れている) ようになります。

{-# LANGUAGE FlexibleContexts #-}

import Control.Monad.Trans (lift)
import Control.Monad.Trans.Resource
import Data.ByteString (ByteString)
import qualified Data.ByteString.Char8 as BC8 (pack)
import Data.Conduit
import qualified Data.Conduit.Binary as Cb
import qualified Data.Conduit.List as Cl
import System.FilePath ((<.>))

test :: IO ()
test =
  runResourceT
      $ Cl.sourceList (fmap (BC8.pack . show) [(1 :: Int)..1000])
     $$ rotateResourceHog "/tmp/foo"

-- |
-- files are allocated on demand but handles are released at the same time
rotateResourceHog
  :: MonadResource m
  => FilePath -> Sink ByteString m ()
rotateResourceHog filePath = step 0 where
  step i = do
    x <- Cl.peek
    case x of
      Just _  -> do
        chunkWriter $ filePath <.> show (i :: Integer)
        -- loop
        step $ i+1

      Nothing -> return ()

-- |
-- files are allocated on demand but handles are released immediately
rotateUsingClosedHandles
  :: (MonadBaseControl IO m, MonadResource m)
  => FilePath -> Sink ByteString m ()
rotateUsingClosedHandles filePath = step 0 where
  step i = do
    x <- Cl.peek
    case x of
      Just _  -> do
        transPipe runResourceT . chunkWriter $ filePath <.> show (i :: Integer)
        -- loop
        step $ i+1

      Nothing -> return ()

chunkWriter
  :: MonadResource m
  => FilePath -> Sink ByteString m ()
chunkWriter filePath = do
  _ <- lift $ allocate (putStrLn "alloc") (\ _ -> putStrLn "free")

  -- the actual conduit chain is more complicated
  Cl.isolate 100 =$= Cb.sinkFile filePath
4

1 に答える 1

2

ResourceT例外的な場合にリソースをクリーンアップすることのみを目的としています。迅速なファイナライズを提供することを意図したものではなく、保証されたファイナライズのみを提供します。迅速さのために、conduitクリーンアップを処理するための独自の機能を提供します。あなたの場合、両方を探しています。クリーンアップをできるだけ早く実行し、例外がスローされた場合でも実行する必要があります。これには、 を使用する必要がありますbracketP。例えば:

chunkWriter
  :: MonadResource m
  => FilePath -> Sink ByteString m ()
chunkWriter filePath = bracketP
    (putStrLn "alloc")
    (\() -> putStrLn "free")
    (\() -> Cl.isolate 100 =$= Cb.sinkFile filePath)

これにより、alloc 出力と free 出力が適切にインターリーブされます。

于 2012-08-16T04:45:11.430 に答える