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.

Другие вопросы по тегам