Способ формирования «выбора» на MVars без опроса - PullRequest
14 голосов
/ 04 мая 2011

У меня есть два MVars (ну, MVar и Chan).Мне нужно вытащить вещи из Чана и обработать их, пока другой MVar больше не станет пустым.Моим идеальным решением было бы что-то вроде функции UNIX select, в которой я передаю список (предположительно пустых) MVars и блоков потоков, пока один из них не заполнится, затем он возвращает полный MVar.Попробуйте, как я мог бы, я не могу думать ни о каком способе сделать это кроме повторного опроса каждого MVar с isEmptyMVar, пока я не получу false.Это кажется неэффективным.

Другая мысль состояла в том, чтобы использовать throwTo, но это прерывает то, что когда-либо происходит в потоке, и мне нужно завершить обработку работы с Чаном атомарным способом.

Последняя мысль, которую я печатаю, заключается в создании нового forkIO для каждого MVar, который пытается прочитать свой MVar, а затем заполнить вновь созданный MVar собственным экземпляром.Исходный поток может затем заблокировать этот MVar.Являются ли потоки на Haskell достаточно дешевыми, чтобы их запускать?

Ответы [ 2 ]

16 голосов
/ 04 мая 2011

Потоки на 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
12 голосов
/ 04 мая 2011

Как насчет использования версий STM, TChan и TVar, с поведением retry и orElse?

Реализация select - одна из приятных возможностей STM. Из «Операции с составной памятью»:

Помимо этого, мы также предоставляем orElse, что позволяет им быть составными как альтернативы, так что вторая запускается, если первая повторная попытка (раздел 3.4). Эта способность позволяет потокам ожидать много вещей одновременно, например, Unix select системный вызов - за исключением того, что orElse хорошо скомпонован, тогда как выбор не делает.


...