Haskell 异步和TBqueue
我有几千个不能同时处理的输出文件,因此我想要一个一次处理n个文件块的函数。所以我决定使用TBQueue 实现的思想是首先用n个伪值填充队列,然后循环尝试读取队列中的下一个伪值。如果队列中有值,则执行IO操作,当IO操作完成时,会向队列中添加一个新值。否则readTBQueue将阻塞,直到其中一个进程完成(至少我希望如此) 我的问题是: 1.当没有更多的文件要处理时,主线程是否要等到所有子线程完成? 2.如果一个异步崩溃会发生什么?是否将在队列上写入伪值Haskell 异步和TBqueue,haskell,asynchronous,stm,Haskell,Asynchronous,Stm,我有几千个不能同时处理的输出文件,因此我想要一个一次处理n个文件块的函数。所以我决定使用TBQueue 实现的思想是首先用n个伪值填充队列,然后循环尝试读取队列中的下一个伪值。如果队列中有值,则执行IO操作,当IO操作完成时,会向队列中添加一个新值。否则readTBQueue将阻塞,直到其中一个进程完成(至少我希望如此) 我的问题是: 1.当没有更多的文件要处理时,主线程是否要等到所有子线程完成? 2.如果一个异步崩溃会发生什么?是否将在队列上写入伪值 processFiles :: Int -
processFiles :: Int -> [FilePath] -> (FilePath -> IO ()) -> IO ()
processFiles n fs fun = do
tbQ <- atomically $ newTBQueue n
atomically $ replicateM_ n $ writeTBQueue tbQ ()
loop fs tbQ
where loop :: [FilePath] -> TBQueue () -> IO ()
loop files queue | null files = return ()
| otherwise = do
join . atomically $ do
readTBQueue queue
let file = head files
return $ withAsync (fun file) $ \a -> do
wait a
atomically $ writeTBQueue queue ()
loop (tail files) queue
processFiles::Int->[FilePath]->(FilePath->IO())->IO()
processFiles n fs fun=do
tbQ TBQueue()->IO()
循环文件队列|空文件=返回()
|否则=做
参加原子级$do
readTBQueue队列
let file=头文件
返回$withAsync(趣味文件)$\a->do
等等
原子$writeTBQueue队列()
循环(尾部文件)队列
根据MathematicalArchid的建议(谢谢!),我编写了一个新的实现
processFiles :: Int -> [FilePath] -> (FilePath -> IO ()) -> IO ()
processFiles n fs fun = do
tbQ <- atomically $ newTBQueue n
loop fs tbQ
where loop :: [FilePath] -> TBQueue FilePath -> IO ()
loop files queue | null files = return ()
| otherwise = do
join . atomically $ do
writeTBQueue queue (head files)
let actionSTM = atomically $ readTBQueue queue
return $ withAsync actionSTM $ \a -> do
file <- wait a
async (fun file) >>= doSomethingOnException
loop (tail files) queue
doSomethingOnException :: Async () -> IO ()
doSomethingOnException a = do
r <- waitCatch a
case r of
Left exception -> undefined
Right _ -> return ()
processFiles::Int->[FilePath]->(FilePath->IO())->IO()
processFiles n fs fun=do
tbQ TBQueue FilePath->IO()
循环文件队列|空文件=返回()
|否则=做
参加原子级$do
writeTBQueue队列(头文件)
让actionSTM=atomically$readTBQueue队列
返回$withAsync actionSTM$\a->do
文件>=doSomethingOnException
循环(尾部文件)队列
doSomethingOnException::Async()->IO()
dosomethingon异常a=do
r未定义
右键->返回()
但我仍然不确定当循环函数返回时,它是否必须等待挂起的作业。这里您似乎有两个不同的问题:同步性和可靠性 STM就是让多个线程访问可变数据而不损坏数据
TBQueue
应该可以处理这个问题。如果您希望“崩溃”操作重新启动。。。你需要为此建立额外的基础设施
是否有特定的原因让您用“虚拟值”而不是(比如)要处理的实际文件名来填充队列?如果是我,主要的威胁是用文件名填充队列(当队列太满时,主线程将被阻塞,而工作线程将执行其工作)。如果要从“崩溃”线程中恢复,则每个线程的每个辅助线程的顶级代码将捕获异常并重试操作或其他操作。或者,这就是我要做的…谢谢!昨天,我试图将文件放入队列中,但未能获得一个有效的实现。然后我想我缺少了一个waitCatchSTM来处理异常。