Vì vậy, vấn đề của tôi là như sau. Tôi đang cố gắng để thực hiện một phân tích cú pháp streaming cho các tập tin RDB (các tập tin dump mà Redis sản xuất). Tôi muốn thực hiện một chức năng tương tự như mapM_ theo đó tôi có thể nói, in ra từng đối tượng được biểu diễn trong tệp kết xuất khi nó được phân tích cú pháp. Tuy nhiên, tôi dường như không thể làm cho nó hoạt động trong không gian liên tục. Tôi thấy rằng những gì đang xảy ra là tôi đang xây dựng một IO lớn() thunk bên trong của Get monad, trở về từ Get monad và sau đó thực thi IO. Có anyway để dòng các đối tượng của tôi khi chúng được phân tích cú pháp để in và sau đó loại bỏ chúng? Tôi đã thử Enumerators và Conduits nhưng tôi đã không nhìn thấy bất kỳ lợi ích thực sự. Dưới đây là những gì tôi có cho đến thời điểm này:IO bên trong Get Monad
loadObjs_ :: (Monad m) => (Maybe Integer -> BL8.ByteString -> RDBObj -> Get (m a)) -> Get (m a)
loadObjs_ f = do
code <- lookAhead getWord8
case code of
0xfd -> do
skip 1
expire <- loadTime
getPairs_ f (Just expire)
0xfc -> do
skip 1
expire <- loadTimeMs
getPairs_ f (Just expire)
0xfe -> f Nothing "Switching Database" RDBNull
0xff -> f Nothing "" RDBNull
_ -> getPairs_ f Nothing
getPairs_ :: (Monad m) => (Maybe Integer -> BL8.ByteString -> RDBObj -> Get (m a)) -> Maybe Integer -> Get (m a)
getPairs_ f ex = do
!t <- getWord8
!key <- loadStringObj False
!obj <- loadObj t
!rest <- loadObjs_ f
!out <- f ex key obj
return (out >> rest)
(loadObj does the actual parsing of a single object but I believe that whatever I need to fix the streaming to operate in constant or near-constant memory is at a higher level in the iteration than loadObj)
getDBs_ :: (Monad m) => (Maybe Integer -> BL8.ByteString -> RDBObj -> Get (m a)) -> Get (m a)
getDBs_ f = do
opc <- lookAhead getWord8
if opc == opcodeSelectdb
then do
skip 1
(isEncType,dbnum) <- loadLen
objs <- loadObjs_ f
rest <- getDBs_ f
return (objs >> rest)
else f Nothing "EOF" RDBNull
processRDB_ :: (Monad m) => (Maybe Integer -> BL8.ByteString -> RDBObj -> Get (m a)) -> Get (m a)
processRDB_ f = do
header <- getBytes 9
dbs <- getDBs_ f
eof <- getWord8
return (dbs)
printRDBObj :: Maybe Integer -> BL8.ByteString -> RDBObj -> Get (IO())
printRDBObj (Just exp) key obj = return $ (print ("Expires: " ++ show exp) >>
print ("Key: " ++ (BL8.unpack key)) >>
print ("Obj: " ++ show obj))
printRDBObj Nothing key RDBNull = return $ (print $ BL8.unpack key)
printRDBObj Nothing key obj = return $ (print ("Key: " ++ (BL8.unpack key)) >>
print ("Obj: " ++ show obj))
main = do
testf <- BL8.readFile "./dump.rdb"
runGet (processRDB_ printRDBObj) testf
Xin cảm ơn tất cả trước.
nhất, Erik
EDIT: Đây là nỗ lực của tôi để phân tích các đối tượng vào một danh sách lười biếng và sau đó IO qua danh sách lười biếng.
processRDB :: Get [RDBObj]
processRDB = do
header <- getBytes 9
dbs <- getDBs
eof <- getWord8
return (dbs)
main = do
testf <- BL8.readFile "./dump.rdb"
mapM_ (print . show) $ runGet processRDB testf
Bạn đã thử http://hackage.haskell.org/package/binary-strict chưa? –
Tôi đã không thử nhị phân nghiêm ngặt nhưng tôi đã cố gắng nhận được nghiêm ngặt của ngũ cốc không có avail. –
Bạn không muốn làm cho nó khắt khe hơn, bạn muốn làm cho nó trở nên lười hơn. Cái gì đó ở đâu đó quá nghiêm ngặt. Nhưng tôi không biết cách của tôi xung quanh các gói có liên quan cũng đủ. –