How can I poll files, sockets or handles to become readable/writable in Haskell?

前端 未结 2 733
难免孤独
难免孤独 2020-11-27 08:07

How could I watch several files/sockets from Haskell and wait for these to become readable/writable?

Is there anything like the select/epoll/... in Haskell? Or I am

相关标签:
2条回答
  • 2020-11-27 08:28

    The question is wrong: you aren't forced to spawn one thread per file/socket and use blocking calls, you get to spawn one thread per file/socket and use blocking calls. This is the cleanest solution (in any language); the only reason to avoid it in other languages is that it's a bit inefficient there. GHC's threads are cheap enough, however, that it is not inefficient in Haskell. (Additionally, behind the scenes, GHC's IO manager uses an epoll-alike to wake up threads as appropriate.)

    0 讨论(0)
  • 2020-11-27 08:40

    There's a wrapper for select(2): https://hackage.haskell.org/package/select
    Example usage here: https://github.com/pxqr/udev/blob/master/examples/monitor.hs#L36

    There's a wrapper for poll(2): https://hackage.haskell.org/package/poll

    GHC base comes with functionality that wraps epoll on Linux (and equivalent on other platforms) in the GHC.Event module.
    Example usage:

    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
    

    More documentation at http://hackage.haskell.org/package/base-4.11.1.0/docs/GHC-Event.html

    Example use of an older version of the lib at https://wiki.haskell.org/Simple_Servers#Epoll-based_event_callbacks Though, the loop in that example has since been moved to the hidden module GHC.Event.Manager, and is not exported publicly as far as I can tell. GHC.Event itself says "This module should be considered GHC internal."

    In Control.Concurrent there's threadWaitRead and threadWaitWrite. So, to translate the above epoll example:

    import Control.Concurrent (threadWaitRead)
    
    main = do
      fd <- getSomeFileDescriptorOfInterest
      threadWaitRead fd
      putStrLn "Got a read ready event"
    

    You can wrap the threadWaitRead and subsequent IO action in Control.Monad.forever to run them repeatedly. You can also wrap the thing in forkIO to run it in the background while your program does something else.

    0 讨论(0)
提交回复
热议问题