Использование Par monad с STM и детерминированным IO - PullRequest
1 голос
/ 14 октября 2011

Я нахожусь в процессе написания отчета для назначения, в котором я реализовал параллельный многоядерный алгоритм ветвления и привязки с использованием пакета STM, и возникла проблема, с которой я столкнулся.

Реализация, которая использует STM, очевидно, находится в монаде ввода-вывода, так как она использует STM «атомарно» и Concurrent «forkIO», но она детерминистична. Несмотря на использование переменной общей памяти, конечный результат функции всегда будет одинаковым для одного и того же ввода.

Мой вопрос: какие у меня есть варианты выхода из ввода-вывода, кроме «unsafePerformIO»? Стоит ли даже пытаться вытащить его из монады ввода-вывода, поскольку использование нескольких ядер может потенциально повлиять на другой параллельный код, который не имеет такой же гарантии детерминизма.

Я слышал о пакете Par monad (хотя он и не использовался), но STM существует в монаде IO, и для получения потоковых глобальных переменных моей единственной альтернативой STM является MVars (о котором я знаю ), которые также существуют в монаде IO.

Ответы [ 2 ]

6 голосов
/ 14 октября 2011

Пожалуйста, не используйте unsafePerformIO с STM. STM имеет побочные эффекты под капотом, использование unsafePerformIO скрывает эти побочные эффекты, делая ваш код обманчиво нечистым и, следовательно, трудным или опасным для рефакторинга. Постарайся понять, поможет ли тебе параллельный пакет.

Одним из примеров небезопасных операций STM, являющихся небезопасными, является случай, когда вы используете «чистую» операцию STM, вложенную в другую (возможно, из библиотеки более высокого уровня). Например, приведенный ниже код повторяется (заканчивается <loop>) из-за вложенных операций STM. Я помню, что старые версии GHC зависали, но сейчас не могу воспроизвести это поведение в GHC 7.0.1.

import Control.Concurrent
import Control.Concurrent.STM
import System.IO.Unsafe
import GHC.Conc.Sync

main = newTVarIO 5 >>= runComputation >>= print

runComputation :: TVar Int -> IO Int
runComputation tv = atomically $ do
        let y = getFiveUnsafe tv + 1
        writeTVar tv y
        return y

getFiveUnsafe tv = unsafePerformIO . atomically $ do
        x <- readTVar tv
        writeTVar tv (x + 5)
        return x

(я приветствую других людей, которые редактируют и добавляют более убедительные примеры - я считаю, что есть лучшие)

0 голосов
/ 25 августа 2016

STM и связанные с ним функции нельзя использовать с unsafePerformIO, но forkIO может быть, и новый поток может безопасно вызывать atomically. Вы можете сделать что-то вроде этого:

purifiedAlgorithm = unsafePerformIO $ do
  rr <- newEmptyMVar
  forkIO $ concurrentAlgorithm >> putMVar rr
  takeMVar rr
...