Как создать параллельную коллекцию Scala из коллекции Java
Самый простой способ преобразовать коллекцию Java в эквивалент Scala - использовать JavaConversions, начиная с Scala 2.8., Эти неявные определения возвращают оболочки для содержащейся коллекции Java.
В Scala 2.9 введены параллельные коллекции, в которых операции над коллекцией могут выполняться параллельно, а результат собирается позднее. Это легко реализовать, преобразовать существующую коллекцию в параллельную так же просто, как:
myCollection.par
Но есть проблема с использованием 'par' для коллекций, преобразованных из коллекций Java с использованием JavaConversion. Как описано в разделе "Преобразования параллельных коллекций", по существу последовательные коллекции "принудительно" превращаются в новую параллельную коллекцию путем оценки всех значений и добавления их в новую параллельную коллекцию:
Другие коллекции, такие как списки, очереди или потоки, по своей сути являются последовательными в том смысле, что элементы должны быть доступны один за другим. Эти коллекции преобразуются в их параллельные варианты путем копирования элементов в похожую параллельную коллекцию. Например, функциональный список преобразуется в стандартную неизменяемую параллельную последовательность, которая является параллельным вектором.
Это вызывает проблемы, когда исходная коллекция Java предназначена для ленивой оценки. Например, если возвращается только Java Iterable, который позднее преобразуется в Scala Iterable, нет гарантии, что к содержимому Iterable можно получить доступ с энтузиазмом или нет. Итак, как следует создавать параллельную коллекцию из коллекции Java без затрат на оценку каждого элемента? Именно этой стоимости я пытаюсь избежать, используя параллельный набор для их параллельного выполнения и, надеюсь, "возьму" первые n предлагаемых результатов.
В соответствии с Parallel Collection Conversions есть ряд типов коллекций, которые стоят постоянного времени, но, похоже, нет способа получить гарантию того, что эти типы могут быть созданы JavaConversions (например, "Set" может быть создан, но что за "HashSet"?).
2 ответа
Во-первых, каждая коллекция, полученная с помощью JavaConversion
s из коллекции Java не является параллелизуемой коллекцией Scala по умолчанию - это означает, что она всегда будет переоцениваться в соответствующую реализацию параллельной коллекции. Причина этого заключается в том, что параллельное выполнение опирается на концепции Splitter
По крайней мере, его нужно разделить на более мелкие подмножества, над которыми затем могут работать разные процессоры.
Я не знаю, как выглядит ваша коллекция Java в смысле структуры данных, но если это древовидная вещь или массив, чьи элементы оцениваются лениво, есть вероятность, что вы легко сможете реализовать Splitter
,
Если вы не хотите с нетерпением force
ленивая коллекция, которая реализует API коллекции Java, тогда единственный вариант - реализовать новый тип параллельной коллекции для этой конкретной коллекции отложенного Java. В этой новой реализации вы должны предоставить средства разбиения итератора (то есть Splitter
).
Как только вы реализуете эту новую параллельную коллекцию, которая знает, как разделить вашу структуру данных, вы должны создать специальную оболочку Scala для вашей конкретной коллекции Java (на данный момент это всего лишь небольшая дополнительная шаблонная таблица, посмотрите, как это делается в JavaConversions
) и переопределить его par
вернуть вашу конкретную параллельную коллекцию.
Вы можете даже сделать это в общем случае для индексированных последовательностей. Учитывая, что ваша коллекция Java представляет собой последовательность (в Java List
) с особенно эффективным get
метод, вы могли бы реализовать Splitter
как итератор, который вызывает get
в начальном диапазоне от 0
в size - 1
и делится путем деления этого диапазона.
Если вы это сделаете, исправления для стандартной библиотеки всегда приветствуются.
Параллель требует произвольного доступа, а java.lang.Iterable не предоставляет его. Это фундаментальное несоответствие: ни одно количество конверсий не поможет вам пройти мимо.
Если использовать аналогию без программирования, вы не можете получить человека из Австралии в Англию, отправив одного человека из Сингапура в Англию, а другого - из Австралии в Сингапур одновременно.
Или в программировании, если вы обрабатываете поток данных в реальном времени, вы не можете распараллелить его, обрабатывая данные с этого момента в то же время, что и данные пять минут назад, без добавления задержки.
Вам нужно что-то, что обеспечивает по крайней мере некоторый произвольный доступ, например, java.util.List.listIterator(Int) вместо Iterable.