我想用“epoll
”式的事件管理,以实现高效的单线程套接字通信。“单子友好”基于事件的IO
如果我写了一个非常必要的程序“从零开始”,我会做它基本上是这样的(我只是打出来只是一些伪代码杂交 - 可能不会编译):
import Control.Concurrent
import Data.ByteString (ByteString)
import qualified Data.ByteString as ByteString
import qualified GHC.Event as Event
import Network
import Network.Socket
import Network.Socket.ByteString
main = withSocketFromSomewhere $ \ socket -> do
let fd = fromIntegral . fdSocket $ socket
-- Some app logic
state <- newMVar "Bla"
-- Event manager
manager <- Event.new
-- Do an initial write
initialWrite socket state manager
-- Manager does its thing
Event.loop manager
write manager socket bs =
-- Should be pretty straight-forward
Event.registerFd manager theWrite fd Event.evtWrite
where
fd = fromIntegral . fdSocket $ socket
theWrite key _ = do
Event.unregisterFd manager key
sendAll socket bs
read manager socket cont =
-- Ditto
Event.registerFd manager theRead fd Event.evtRead
where
fd = fromIntegral . fdSocket $ socket
theRead key _ = do
Event.unregisterFd manager key
bs <- recv socket 4096
cont bs
initialWrite socket state manager = do
msg <- readMVar state
write manager socket msg
read manager socket $ \ bs -> do
ByteString.putStrLn bs
putMVar state msg
试想一下,也有一些函数,添加超时事件的经理,和这样的。
然而,这个代码不是特别漂亮,有几个原因:
- 我周围的事件管理器进行手动。
- 我必须使用
MVar
我的应用程序逻辑,因为我不能告诉不透明的事件管理器,它应该通过周围的一些国家对我来说,虽然我知道,它仅使用一个线程,因此有可能被用来作为monad变压器堆栈的基础。 - 我要创建明确界定为延续读取(我甚至可能为写入做到这一点,我不知道会是什么在这种情况下更聪明)。
现在,这只是尖叫的使用单子变压器等过多的我想能够只是做到这一点:
main =
withSocketFromSomewhere $ \ socket ->
runEvents . flip runStateT "Bla" $ initialWrite socket
initialWrite socket = do
msg <- lift get
write socket msg
resp <- read socket
liftIO $ ByteString.putStrLn resp
lift $ put msg
此代码应该有相同的行为以上代码;例如通过暂停计算,直到读已经在resp <- read socket
线接收,并让我管理在同一个线程/多经理插座。
问题:
- 有没有更高层接口给GHC事件API/libevent的/当量,为用户提供更多的权力?考虑到近期GHC发生的同步IO调度更改(我在7.4.1),它甚至值得吗?
- 如果我想实现协同并发,例如通过一个函数总是处理来自套接字的读取操作,但是该函数与写入“线程”共享相同的状态monad,会怎么样?这可以用(1)的解决方案来完成吗?
这非常有趣。我想一个相关的已经存在的Haskell概念是[Coroutine monad](http://hackage.haskell.org/package/monad-coroutine)(它构成了一个免费的monad)。协程基本上可以让你将任何仿函数作为一个带有“暂停”的免费monad,它可以让你跳过必须解释与读/写无关的“无趣的东西”。我会尝试这种方法,现在就接受这个解决方案。 – dflemstr 2012-04-28 18:28:50
是的,我实际上实现了这个“免费单体变压器”,Ross计划将其包含在下一个“变形金刚”版本中。你可以看到我的实现[这里](https://github.com/Gabriel439/Haskell-Pipes-Library/blob/master/Control/Monad/Trans/Free.hs)。我将它用于我的'管道'库。 – 2012-04-28 19:36:15
如果一个免费的monad是一个变压器,那么您如何引入诸如'forkIO'等功能?如何在IO monad中“monad stack”被串行化?那部分对我来说毫无意义。 – dflemstr 2012-04-28 20:14:17