Haskell: попытка параллельной реализации `atomicModifyIORef`
Из того, что я понимаю, модификации к IORef
Они очень быстрые, все, что они включают, это обновление указателя thunk. Конечно, читателю (то есть тому, кто хочет увидеть значение на своей веб-странице) потребуется время, чтобы оценить эти результаты (которые могут возникнуть, если авторы не читают результаты).
Я подумал, что было бы хорошо, чтобы начать на самом деле оценки модификации Thunks на IORef
параллельно, так как во многих случаях их, вероятно, придется в какой-то момент оценивать (очевидно, это будет нарушаться бесконечными структурами данных).
Итак, я написал следующую функцию с похожей подписью atomicModifyIORef
:
atomicModifyIORefPar :: (NFData a) => IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORefPar ioref f =
let
g olddata =
let (newdata, result) = f olddata in (newdata, (result, newdata))
in do
(result, newdata) <- atomicModifyIORef ioref g
force newdata `par` return result
Это похоже на работу ( тестовый код здесь). Что-то я тут не так сделал? Или есть лучший способ сделать это?
Изменить: вторая попытка
Вдохновленный ответом Карла ниже. Мы на самом деле храним force newdata
в IORef
, Это так же, как newdata
в любом случае, но показывает время выполнения, которое мы хотим сохранить force newdata
на потом, чтобы он не собирал мусор.
atomicModifyIORefPar :: (NFData a) => IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORefPar ioref f =
let
g olddata =
let
(newdata, result) = f olddata
newdata_forced = force newdata
in
(newdata_forced, (result, newdata_forced))
in do
(result, newdata_forced) <- atomicModifyIORef ioref g
newdata_forced `par` return result
1 ответ
Это может или не может работать, в зависимости от версии GHC. Взаимодействие искрового пула с GC на протяжении истории было переменным. В некоторых версиях тот факт, что выражение force newdata
не упоминается ничего по объему после atomicModifyIORefPar
возврат означает, что это может быть мусором до искры, созданной par
когда-либо преобразуется, что означает, что искра также будет собрана.
Другие версии GHC рассматривали искровой пул как корни в анализе GC, но это также имеет проблемы. Я не помню, каково текущее состояние, но я подозреваю, что искровой пул не считается корнями GC. Возникающие проблемы (потеря параллелизма, когда возвращаемые выражения не ссылаются на выражения, вычисляемые параллельно) менее серьезны, чем проблемы, возникающие при обработке искрового пула как корней GC (сохранение памяти, которая не нужна).
Изменить - вторая попытка ответа
Эта новая реализация выглядит правильно по указанным вами причинам. Выражение, вычисляемое параллельно, также доступно из корней GC.