2016-03-07 31 views
0

我很努力用DB操作(SqlPersistM)编写forkIO的最佳方法。注意:SqlPersistM定义为here,基本上是ReaderT SqlBackend (NoLoggingT (ResourceT IO))。这里是有问题的代码的简化版本:如何撰写forkIO和SqlPersistM

startBot :: SqlPersistM() 
startBot = do 
    chan <- liftIO newChan 
    forkIO $ forever (processIncomingMessages chan) -- How to do do this? 
    forkIO $ forever (processOutgoingMessages chan) -- And this? 
    return() 

processIncomingMessages :: Chan -> SqlPersistM() 

processOutgoingMessages :: Chan -> SqlPersistM() 

main = runSqlite ":memory:" startBot 

它甚至有可能到餐桌SqlPersistM动作传递给runSqlite?或者应该把runSqlite行动放在叉子里面?前者会导致“竞赛条件”的排序吗?线程是否能够同步他们对底层数据库连接的使用?

更多上下文:processIncomingMessages接收来自网络API的输入,解析它们并将它们推送到chanprocessOutgoingMessageschan读取,运行一些转换并将数据发送到不同的网络API。在处理传入/传出消息时,这两个函数都与数据交互。

+0

有人可以解释为什么我得到了downvote?这些问题在这里不受鼓励吗? –

+0

您是否知道['resourceForkIO'](https://hackage.haskell.org/package/resourcet-1.1.7/docs/Control-Monad-Trans-Resource.html#v:resourceForkIO)。从文档 - “如果你正在分配一个应该被多个线程共享的资源,并且会被保存很长时间,你应该在新的ResourceT块的开头分配它,然后从那里调用resourceForkIO。”我相信它适合你的使用案例 - “永远”是一个很长的时间,你担心并发访问。 – user2407038

+0

为了更直接地解决您的问题 - 如果您在程序中使用“原始”并发性,事情最终可能会中断。但是似乎'持久化'的设计者已经认识到了这个问题,并且在monad栈中包含了一个'ResourceT' monad,所以用户有一个可接受的方式来处理它。 – user2407038

回答

2

是的,对于运行SqlPersistM您需要runSqlite。至于获得竞争条件,我认为这取决于sqlite本身。检查它是否允许并发访问。

因为forkIO和其他异步的东西只在IO工作,没有办法在里面拖动SqlPersistM。那么,因为它基本上是一个ReaderT,你可能可以,但我敢打赌这不是它打算如何使用。所以,国际海事组织,你需要首先分叉线程,然后使用runSqlite内部运行持久性动作。

+0

,因为'startBot'正在进行数据库访问。 –

+0

感谢您更新您的答案。你能否详细说明一段代码?我无法理解。 –

+0

对不起,我错了'forkFinally'。你可能需要使用一些像'Chan'或'MVar'这样的原语。 – arrowd