У меня есть функция, которая выполняет один шаг вычислений путем обновления карты (в основе лежит изменяемый HashMap). Я хочу сделать несколько таких вычислений параллельно (каждая «цепочка» работает со своим изменяемым HashMap).
Я сделал это, поместив HashMaps в параллельную коллекцию и применив функцию к каждому HashMap, используя map.
Теперь я испытал пропущенные записи на картах. При отладке карта содержит запись, как только точка останова исключения останавливает программу (и тогда перезапуск вычисления немного раньше, отбрасывая некоторые слои стековых фреймов).
Это поведение исчезает, когда я использую последовательные коллекции. Так возможно ли, что есть какое-то неправильное поведение (или ошибка), вызванное тем, что один и тот же HashMap работает в разных потоках?
Я не опубликовал пример кода, так как я не думаю, что поведение воспроизводимо. Насколько мне известно, единственные изменяемые данные содержатся внутри тех HashMaps, которые содержат состояние вычислений.
По запросу образец моего кода, в котором создается параллельная карта (reset
) и изменяется (step
).
class ParallelInferer[V <: DiscreteVariable, TInf <: InferenceAlgorithm[V]](val numChains: Int,
val inferer: InferenceAlgorithm[V],
val random: Random) {
//tuples of inferer state and the according random number generator
protected var states: ParSeq[(inferer.Repr,Random)] = _
protected var steps = 0
reset()
def reset() {
steps = 0
val seed = random.nextInt()
//todo why does parallelizing fail here (key not found on a map)
states = (1 to numChains).par
.map(n => new Random(seed + n)) //create the rngs
.map(rng => (inferer.createInitialState(rng),rng))
}
def step() {
//advance every chain by one
states = states.map{case (repr, rng) => (inferer.computeStep(repr, rng),rng)}
steps = steps + 1
}
}
Пояснение к коду
Класс ParallelInferer
предназначен (также) для неизменного вывода. Таким образом, изменчивость не видна непосредственно в опубликованном коде, но я думаю, что это важная часть, которая показана.
У каждого алгоритма логического вывода есть понятие состояния, это состояние имеет тип InferenceAlgorithm#Repr
- как видно из использования inferer.Repr
как части переменной states
. Логические устройства работают путем отображения Repr
(и объекта Random) на новый Repr
с их функцией computeStep
. Это можно увидеть в def step()
. Теперь некоторые умельцы используют изменяемый HashMap
как часть своего состояния. Их метод computeStep
возвращает ту же карту, которую он получил в качестве аргумента, после ее изменения.
Вопрос
- Можно ли как-то исправить это поведение?
- Неправильно ли я использую параллельные коллекции и нужно ли распараллеливать мою задачу иначе?
Редактировать
Я только что снова запустил распараллеленную версию, и я думаю, что это также приводит к тому, что алгоритм не завершает работу, хотя это происходит при последовательной работе. Ну, не , что удивительно, не правда ли?
Может кто-нибудь порассуждать о том, почему это происходит?