Как реализовать эффективную параллельную «сумку» для JavaJAVA

Программисты JAVA общаются здесь
Anonymous
Как реализовать эффективную параллельную «сумку» для Java

Сообщение Anonymous »

Мне нужна наиболее общая реализация изменяемой коллекции.
Операции
Единственные операции, которые меня интересуют:
  • Добавление нового элемента в коллекцию;
  • Обход в любом порядке;
  • Завершение коллекции, предотвращение добавления дополнительных элементов добавляется.
Ограничения
Применяются дополнительные ограничения:
  • Обход не должен препятствовать добавлению новых элементов во время его выполнения; скорее, добавленные элементы должны быть включены в обход.
  • После завершения обхода мне нужно атомарно проверить простое условие на основе результата, вычисленного для пройденных элементов, и, возможно, закрыть коллекцию для будущих добавлений.
  • Атомарно означает, что ни один элемент не должен быть потерян; любые добавления, происходящие после завершения обхода, но до принятия решения должны дождаться результата этого решения.
  • Операции добавления синхронно и атомарно информируют вызывающую сторону, если это удалось;
  • Алгоритм свертывания/накопления элементов всегда один и тот же, т. е. мне не нужно заботиться о помехах между обходами. Не ожидается, что более одного потока будут пытаться пройти обход одновременно, но если это произойдет, он должен просто дождаться завершения другого, если необходимо, но
  • Обработка результата обхода может происходить асинхронно, если это необходимо, то есть достаточно, чтобы вызов обхода асинхронно отправлял вызов на выполнение, если он запускается как можно скорее.
  • Добавление может произойти в спорной среде; в этом случае все потоки не должны синхронизироваться при обновлении одного и того же состояния (например, ссылка на связанный список). Точнее, оптимистичная атомарная проверка и установка ссылки на неизменяемый список приемлема по умолчанию, но неудача слишком много раз глобально для каждой коллекции должна привести к использованию по умолчанию чего-то с меньшей синхронизацией (проблема не в атомарном обновлении ссылки, а в необходимости создания нового объекта; выполните дополнительную операцию между чтением и записью).
  • Коллекция должен самонастраиваться; уровень параллелизма заранее неизвестен.
Дизайн
Грубо говоря, я представляю себе массив связанных списков, в котором потоки работают в корзине на основе хэша идентификатора потока, где размер массива может увеличиваться в зависимости от некоторого эвристического обнаружения конфликтов. Возможна ли вообще такая адаптация?
Чтобы лучше проиллюстрировать то, о чем я думаю, приведу очень неправильный псевдокод:

Код: Выделить всё

boolean add(Elem elem) {
if (closed())
return false
if (this.state == TRAVERSAL) //obviously a race condition
return beCarefulIGuess()
//The collection starts with a single bucket, but that number may increase
// based on atomicFailureInc() step.
Bucket bucket = getBucket()
Link list = bucket.list
Link newList = new Link(elem, list)
int state;
while ((state = atomicTestAndSet(bucket, list, newList) != SUCCESS) {
if (state == CLOSED) //Obviously, a race condition here...
return false
if (state == TRAVERSAL)
//???
if (state == TRAVERSAL_END)
//Do not add new elements when the traversal happening now finished,
// but did not made the decision if further adding is allowed.
wait()
list = bucket.list
newList.tail = list
atomicFailureInc()
//If some magical threshold is exceeded, the collection should convert
// to more buckets, but not necessarily now.
}
return true
}
Я думаю, что двойного решения: либо одного сегмента, либо количества сегментов, равного удвоенному количеству ядер, может быть достаточно, надеюсь? Закрытое хеширование с хорошей хэш-функцией для таблицы, размер которой в два раза превышает количество хранимых элементов, кажется практическим правилом для доступа O(1) в обычных реализациях HashSet. Это не учитывает возможность замены потока при удержании блокировки, но при очень коротких критических участках это не должно происходить слишком часто. Ошибки можно подсчитывать с помощью чего-то вроде Adder и время от времени проверять общее количество.
Этот вопрос не требует наличия готовой библиотеки. Просто самый разумный способ удовлетворить эти требования. Может быть научная статья (цитирование по данной ссылке разрешено). Я не ожидаю, что кто-то внедрит это только ради моей выгоды, но предоставление описания структуры данных с ее инвариантами направит меня на правильный путь.

Вернуться в «JAVA»