【问题标题】:Waiting on two inputs in Haskell, simultaneously在 Haskell 中同时等待两个输入
【发布时间】:2010-01-11 06:23:39
【问题描述】:

标题可能有点模糊。这就是我的意思:

假设我有两种方法可以获取程序的输入。第一种是通过键盘,使用函数getLine 阻塞直到读取一行。另一种是,比如说,通过TChan,其中使用readTChan chan 也会导致阻塞,直到通道中存在一个值,然后才会读取它。

我想要完成的是能够等待 both 值,使用单个线程并且不允许我的 CPU 跳转到 100%。当两个值之一可用时,它被获取并且程序恢复。 (比如说,使用Either 通知接收到了两个值中的哪一个。)

这可能吗?

非常感谢!

【问题讨论】:

  • 让一个 IO 线程调用 getLine 并将其结果也放入 TChan 怎么样?在我看来它应该可以工作..
  • 为什么要使用单线程?例如,如果您需要等待 3 个输入怎么办?还是5?还是10?为什么要随意限制?
  • 我猜你有一些代码在使用多个线程并且你有 100% 的 CPU?您可能想发布代码以便其他人了解原因:正确的解决方案是线程,它可能只是一个实现问题。

标签: haskell concurrency io


【解决方案1】:

我认为“使用单线程”在这里没有意义。无论如何,您必须已经在使用多个 Haskell 线程来写入 TChan。您应该使用两个 Haskell 线程来执行此操作,并使用 MVar 或类似的来传达要到达的第一个结果。例如:

module Main where

import System.IO
import Control.Concurrent
import Control.Concurrent.MVar
import Control.Concurrent.STM
import Control.Concurrent.STM.TChan

main = do
   chan <- newTChanIO
   forkIO (threadTChanWrite chan)
   threadMultiplexedRead chan

threadTChanWrite chan = do
   threadDelay 5000000
   atomically $ writeTChan chan 3

threadMultiplexedRead chan = do
   mvar <- newEmptyMVar
   forkIO (threadKeyboardRead mvar)
   forkIO (threadTChanRead mvar chan)
   v <- readMVar mvar
   print v

threadKeyboardRead mvar = do
   str <- getLine
   putMVar mvar (Right str)

threadTChanRead mvar chan = do
   v <- atomically (readTChan chan)
   putMVar mvar (Left v)

顺便说一句,一个适当的实现可能会清理剩下的线程。

【讨论】:

    【解决方案2】:

    我有两种获取程序输入的方法

    您应该能够使用 2 个线程,每个输入源一个,等待各自的输入,将结果写入共享通道或由第三个线程控制的 mvar。

    【讨论】:

    • @Charles 你没抓住重点。不使用多个线程是毫无意义的,而且这家伙甚至没有说出原因。
    • 他不需要说为什么,我不明白我们怎么知道这个愿望是没有意义的。
    • 我认为 OP 期望的是 OS 线程,而不是 Haskell 线程(延续)。由于 Haskell 线程只是两个延续,这确实是一个更好的解决方案......事实上,我们所有的解决方案都使用多个 Haskell 线程来交错 IO,正如公认的答案一样......
    【解决方案3】:

    在hackage的“async”包中有race :: IO a -&gt; IO b -&gt; IO (Either a b)辅助函数。

    同时运行两个 IO 操作,因此一个可能是您的 getLine 而另一个阻塞 MVar 或其他。返回一个Either,表示哪个先返回(另一个被取消)。

    https://hackage.haskell.org/package/async-2.0.2/docs/Control-Concurrent-Async.html#v:race

    【讨论】:

    • IMO 这是正确的答案。接受的答案过于复杂,这个答案执行接受答案所说的整理。你必须有充分的理由使用forkIO 而不是async
    猜你喜欢
    • 1970-01-01
    • 2020-06-24
    • 2019-05-08
    • 1970-01-01
    • 1970-01-01
    • 2020-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多