Способ формирования "выбора" на MVars без опроса
У меня есть два MVars (ну, MVar и Чан). Мне нужно вытащить вещи из Чана и обработать их, пока другой MVar больше не будет пустым. Моим идеальным решением было бы что-то вроде UNIX select
функция, в которой я передаю список (предположительно пустых) MVars и блоков потоков, пока один из них не заполнится, затем он возвращает полный MVar. Попробуйте, как я мог бы, я не могу думать ни о каком способе сделать это кроме повторного опроса каждого MVar с isEmptyMVar, пока я не получу false. Это кажется неэффективным.
Другая идея заключалась в том, чтобы использовать throwTo, но это прерывает то, что когда-либо происходит в потоке, и мне нужно завершить обработку работы с Чаном атомарным способом.
Последняя мысль, которую я набираю, - создать новый forkIO для каждого MVar, который пытается прочитать свой MVar, а затем заполнить вновь созданный MVar своим собственным экземпляром. Исходный поток может затем заблокировать этот MVar. Являются ли потоки на Haskell достаточно дешевыми для запуска такого количества?
2 ответа
Потоки на Haskell очень дешевы, так что вы можете решить их таким образом, но, похоже, STM лучше подойдет для вашей проблемы. С STM вы можете сделать
do var <- atomically (takeTMVar a `orElse` takeTMVar b)
... do stuff with var
Из-за поведения retry
а также orElse
этот код пытается получить a
тогда, если это не удастся, получите b
, Если оба сбоя, он блокируется, пока один из них не будет обновлен и пытается снова.
Вы даже можете использовать это, чтобы сделать свою собственную элементарную версию select
:
select :: [TMVar a] -> STM a
select = foldr1 orElse . map takeTMVar
Как насчет использования версий STM, TChan
а также TVar
с retry
а также orElse
поведение?
Реализация select - одна из приятных возможностей STM. Из "Композиционные транзакции памяти":
Помимо этого, мы также предоставляем orElse, который позволяет им составляться как альтернативы, так что вторая запускается, если первая попытка повторяется (раздел 3.4). Эта способность позволяет потокам одновременно ожидать много вещей, как, например, системный вызов select Unix - за исключением того, что orElse хорошо скомпонован, а select - нет.
orElse
в RWH.- Пакет СТМ
- Документы на STM Хаскелла