在Haskell中异步读取行

时间:2018-12-10 21:34:39

标签: haskell asynchronous

我尝试读取行而不使用Async进行阻止。我已经弄清楚了如何阅读一行,但是我不知道使这一行连续的正确方法。理想情况下,我希望有一个生成器,可以在不阻塞主循环的情况下读取下一行。我该怎么办?

module Main where

import Control.Concurrent
import Control.Concurrent.Async

-- New async reader
main :: IO ()
main = do
  getl <- async getLine
  mainLoop getl

-- Read stdin and echo forever
mainLoop :: Async String -> IO ()
mainLoop getl = do
  tryRead getl >>= tryPrint
  threadDelay $ 1000 * 1000
  mainLoop getl

-- Try to read stdin without blocking
tryRead :: Async String -> IO (Maybe String)
tryRead recvr = do
  res <- poll recvr
  case res of
    Nothing -> return Nothing
    Just (Right a) -> return $ Just a
    Just (Left e) -> error $ show e

-- Try to print string
tryPrint :: Maybe String -> IO ()
tryPrint (Just str) = print str
tryPrint Nothing = return ()

输出。我假设发生的事情是,第一次对Async getline进行了评估,然后在每次轮询Async时都返回该值。

hell
"hell"
"hell"
"hell"
"hell"
"hell"

2 个答案:

答案 0 :(得分:1)

使用unagi-chan的频道流的更好解决方案。

module Main where

import Control.Monad
import Control.Concurrent hiding (newChan, writeChan)
import Control.Concurrent.Chan.Unagi.NoBlocking

main :: IO ()
main = do
  (inchan, outchan) <- newChan
  _ <- forkIO $ getStdin inchan
  [stream] <- streamChan 1 outchan
  mainLoop stream

mainLoop :: Stream String -> IO ()
mainLoop stream = do
  (str, stream') <- getNext stream
  forM_ str print
  threadDelay 1000
  mainLoop stream'

getStdin :: InChan String -> IO ()
getStdin chan = forever $ getLine >>= writeChan chan

getNext :: Stream String -> IO (Maybe String, Stream String)
getNext stream = do
  next <- tryReadNext stream
  case next of
    Next str stream' -> return (Just str, stream')
    Pending -> return (Nothing, stream)

答案 1 :(得分:0)

虽然有些丑陋,但我还是一起破解了一些似乎可行的东西。 tryRead现在返回下一个要轮询的异步,它是旧的异步事件还是新的异步事件。 我想消除传递异步事件的必要性,但是我想现在就可以了。

module Main where

import Control.Concurrent
import Control.Concurrent.Async

-- New async reader
main :: IO ()
main = mainLoop Nothing

-- Read stdin and echo forever
mainLoop :: Maybe (Async String) -> IO ()
mainLoop getl = do
  (res, getl') <- tryRead getl
  tryPrint res
  threadDelay 1000
  mainLoop (Just getl')

-- Try to read stdin without blocking
tryRead :: Maybe (Async String) -> IO (Maybe String, Async String)
tryRead Nothing = do
  recvr <- async getLine
  return (Nothing, recvr)
tryRead (Just recvr) = do
  res <- poll recvr
  case res of
    Nothing -> return (Nothing, recvr)
    Just (Right a) -> do recvr' <- async getLine
                         return (Just a, recvr')
    Just (Left e) -> error $ show e

-- Try to print string
tryPrint :: Maybe String -> IO ()
tryPrint (Just str) = print str
tryPrint Nothing = return ()