我如何从Haskell观看几个文件/套接字并等待它们变得可读/可写?
在Haskell中有类似select / epoll / ...的内容吗?或者我被迫为每个文件/套接字生成一个线程并始终使用该线程中的阻塞资源?
答案 0 :(得分:14)
问题是错误的:你不是强制为每个文件/套接字生成一个线程并使用阻塞调用,你获取每个文件/套接字产生一个线程并使用阻止调用。这是最干净的解决方案(任何语言);在其他语言中避免它的唯一原因是那里的效率有点低。然而,GHC的线程足够便宜,它在Haskell中效率不高。 (此外,在幕后,GHC的IO管理器使用类似epoll的方式来唤醒线程。)
答案 1 :(得分:2)
select(2)
有一个包装:https://hackage.haskell.org/package/select
此处使用示例:https://github.com/pxqr/udev/blob/master/examples/monitor.hs#L36
poll(2)
有一个包装器:
https://hackage.haskell.org/package/poll
GHC base附带了在GHC.Event
模块中包装epoll on Linux(以及其他平台上的等效内容)的功能。
用法示例:
import GHC.Event
import Data.Maybe (fromMaybe)
import Control.Concurrent (threadDelay)
main = do
fd <- getSomeFileDescriptorOfInterest
mgr <- fromMaybe (error "Must be compiled with -threaded") <$> getSystemEventManager
registerFd mgr (\fdkey event -> print event) fd evtRead OneShot
threadDelay 100000000
http://hackage.haskell.org/package/base-4.11.1.0/docs/GHC-Event.html
的更多文档在https://wiki.haskell.org/Simple_Servers#Epoll-based_event_callbacks使用旧版lib的示例
但是,该示例中的loop
已被移至隐藏模块GHC.Event.Manager
,并且据我所知,并未公开导出。 GHC.Event
本身说“这个模块应该被视为GHC内部。”
在Control.Concurrent
threadWaitRead
和threadWaitWrite
。
所以,要翻译上面的epoll例子:
import Control.Concurrent (threadWaitRead)
main = do
fd <- getSomeFileDescriptorOfInterest
threadWaitRead fd
putStrLn "Got a read ready event"
您可以将threadWaitRead
及后续IO操作包装在Control.Monad.forever
中以重复运行它们。您还可以将事物包装在forkIO
中,以便在程序执行其他操作时在后台运行它。