docs говорят:
В параллельной программе операции IORef могут отображаться вне порядка другой поток, в зависимости от модели памяти базового архитектуры процессора... Реализация необходима для обеспечения того, чтобы переупорядочение операций с памятью не может привести к правилу ввода кода неправильно. В частности, при проверке значения, считанного с IORef, запись в памяти, которая создала это значение, должно происходить из точка зрения текущего потока.
Я даже не совсем уверен, как разбираться. Эдвард Ян говорит
Другими словами, "Мы не даем никаких гарантий относительно переупорядочения, за исключением того, что у вас не будет никаких нарушений безопасности типа."... последнее предложение отмечает, что IORef не может указывать на неинициализированная память
Итак... он не сломает весь haskell; не очень полезно. обсуждение, из которого возник пример модели памяти, также оставил меня с вопросами (даже Саймон Марлоу, казалось, немного удивился).
Вещи, которые мне кажутся понятными из документации
-
в потоке an
atomicModifyIORef
"никогда не наблюдается перед любыми более ранними операциями IORef или после каких-либо последующих операций IORef", то есть мы получаем частичный порядок: материал выше атомного mod → атомного mod → материал после. Хотя формулировка "никогда не наблюдается" здесь указывает на жуткий ход, которого я не ожидал. -
A
readIORef x
может быть перенесен доwriteIORef y
, по крайней мере, когда нет зависимостей данных -
Логически я не вижу, как что-то вроде
readIORef x >>= writeIORef y
можно переупорядочить
Что мне непонятно
-
Будет ли
newIORef False >>= \v-> writeIORef v True >> readIORef v
всегда возвращатьсяTrue
? -
В случае
maybePrint
(из документов IORef) был быreadIORef myRef
(а также, возможно,seq
или что-то еще) доreadIORef yourRef
, вызвавшего барьер для переупорядочения?
Какую прямую ментальную модель я должен иметь? Это что-то вроде:
внутри и с точки зрения отдельного потока, упорядочение операций IORef будет казаться разумным и последовательным; но компилятор может фактически переупорядочить операции таким образом, чтобы разрыв некоторые предположения в параллельной системе; однако, когда поток
atomicModifyIORef
, никакие потоки не будут наблюдать операции над этимIORef
, который появился надatomicModifyIORef
, чтобы произойти после, и наоборот.
...? Если нет, то какая исправленная версия выше?
Если ваш ответ "не используйте IORef
в параллельном коде, используйте TVar
", пожалуйста, убедите меня в конкретных фактах и конкретных примерах того, о чем вы не можете рассуждать с помощью IORef
.