我很努力用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