我很努力用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的输入,解析它们并将它们推送到chan
。 processOutgoingMessages
从chan
读取,运行一些转换并将数据发送到不同的网络API。在处理传入/传出消息时,这两个函数都与数据交互。
有人可以解释为什么我得到了downvote?这些问题在这里不受鼓励吗? –
您是否知道['resourceForkIO'](https://hackage.haskell.org/package/resourcet-1.1.7/docs/Control-Monad-Trans-Resource.html#v:resourceForkIO)。从文档 - “如果你正在分配一个应该被多个线程共享的资源,并且会被保存很长时间,你应该在新的ResourceT块的开头分配它,然后从那里调用resourceForkIO。”我相信它适合你的使用案例 - “永远”是一个很长的时间,你担心并发访问。 – user2407038
为了更直接地解决您的问题 - 如果您在程序中使用“原始”并发性,事情最终可能会中断。但是似乎'持久化'的设计者已经认识到了这个问题,并且在monad栈中包含了一个'ResourceT' monad,所以用户有一个可接受的方式来处理它。 – user2407038