Ожидание на двух входах в Haskell, одновременно - PullRequest
8 голосов
/ 11 января 2010

Название может быть немного расплывчатым. Вот что я имею в виду:

Скажем, у меня есть два способа получить информацию о моей программе. Первый - через клавиатуру с использованием функции getLine, которая блокирует чтение строки. Другой, скажем, через TChan, где использование readTChan chan также приведет к блоку, пока значение не появится в канале, после чего оно будет прочитано.

То, чего я хочу достичь, - это ждать обоих значений, используя один поток и не позволяя моему ЦП перейти на 100%. В тот момент, когда доступно одно из двух значений, оно извлекается и программа возобновляет работу. (Скажите, используя Either, чтобы уведомить, какое из двух значений было получено.)

Возможно ли это?

Большое спасибо!

Ответы [ 3 ]

12 голосов
/ 11 января 2010

Я не думаю, что "использование одного потока" имеет здесь смысл. В любом случае, вы уже должны использовать несколько потоков на 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)

Надлежащая реализация, вероятно, очистит оставшиеся после этого потоки, кстати.

5 голосов
/ 11 января 2010

У меня есть два способа получить данные для моей программы

Вы должны иметь возможность использовать 2 потока, по одному на каждый источник ввода, которые ожидают на своих соответствующих входах, записывая результат в общий канал или mvar, управляемый третьим потоком.

2 голосов
/ 25 ноября 2015

В пакете "async" при взломе есть вспомогательная функция race :: IO a -> IO b -> IO (Either a b).

Запускает два действия ввода-вывода одновременно, так что одно может быть вашим getLine, а другое - блокировкой MVar или чем-то еще. Возвращает Either, указывающий, какой из них возвратился первым (другой отменен).

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

...