Как создать параллельную коллекцию Scala из коллекции Java

Самый простой способ преобразовать коллекцию Java в эквивалент Scala - это использовать JavaConversions, начиная с версии Scala 2.8.. Эти неявные defs возвращают оболочки для содержащейся коллекции Java.

В Scala 2.9 появились параллельные коллекции, в которых операции с коллекцией могут выполняться параллельно, а результат собираться позже. Это легко реализовать, преобразовать существующую коллекцию в параллельную так же просто, как:

myCollection.par

Но есть проблема с использованием par в коллекциях, преобразованных из коллекций Java с помощью JavaConversions. Как описано в Параллельные преобразования коллекций, по своей сути последовательные коллекции - это ' принудительно 'в новую параллельную коллекцию, оценив все значения и добавив их в новую параллельную коллекцию:

Другие коллекции, такие как списки, очереди или потоки, по своей сути последовательны в том смысле, что к элементам необходимо обращаться один за другим. Эти коллекции преобразуются в их параллельные варианты путем копирования элементов в аналогичную параллельную коллекцию. Например, функциональный список преобразуется в стандартную неизменяемую параллельную последовательность, которая представляет собой параллельный вектор.

Это вызывает проблемы, когда исходная коллекция Java предназначена для ленивой оценки. Например, если возвращается только Java Iterable, позже преобразованный в Scala Iterable, нет гарантии, что содержимое Iterable предназначено для быстрого доступа или нет. Итак, как следует создать параллельную коллекцию из коллекции Java, не поддерживая затраты на оценку каждого элемента? Я пытаюсь избежать этой стоимости, используя параллельную коллекцию для их параллельного и, надеюсь, выполнения » возьмите первые n предложенных результатов.

Согласно Параллельные преобразования коллекций, существует ряд типов коллекций это требует постоянного времени, но, похоже, нет способа получить гарантию того, что эти типы могут быть созданы с помощью JavaConversions (например, «Set» может быть создан, но является ли это «HashSet»?).


person Dan Gravell    schedule 12.10.2012    source источник
comment
Обратите внимание, что было бы лучше использовать JavaConverters, а не JavaConversions в качестве последнего, с этим там вы могли бы сделать что-то вроде .asScala.toList.par.   -  person Sean Parsons    schedule 12.10.2012


Ответы (2)


Во-первых, каждая коллекция, полученная через JavaConversions из коллекции Java, не является по умолчанию распараллеливаемой коллекцией Scala - это означает, что она всегда будет переоцениваться в соответствующей реализации параллельной коллекции. Причина этого в том, что параллельное выполнение основывается на концепции _ 2_s как минимум - он должен быть разделен на более мелкие подмножества, с которыми затем могут работать разные процессоры.

Я не знаю, как ваша коллекция Java выглядит с точки зрения структуры данных, но если это древовидная вещь или массив, элементы которого оцениваются лениво, есть вероятность, что вы легко сможете реализовать Splitter.

Если вы не хотите с нетерпением force ленивую коллекцию, которая реализует API коллекции Java, тогда ваш единственный вариант - реализовать новый тип параллельной коллекции для этой конкретной отложенной коллекции Java. В этой новой реализации вы должны предоставить средства разделения итератора (то есть Splitter).

После того, как вы реализуете эту новую параллельную коллекцию, которая знает, как разделить вашу структуру данных, вы должны создать настраиваемую оболочку Scala для вашей конкретной коллекции Java (на данный момент это всего лишь небольшой дополнительный шаблон, посмотрите, как это делается в JavaConversions) и переопределите его par, чтобы вернуть конкретную параллельную коллекцию.

Возможно, вы даже сможете сделать это в общем для индексированных последовательностей. Учитывая, что ваша коллекция Java представляет собой последовательность (в Java, List) с особенно эффективным get методом, вы можете реализовать Splitter как итератор, который вызывает get в начальном диапазоне от 0 до size - 1 и разделяется путем деления этого диапазона.

В этом случае всегда приветствуются патчи к стандартной библиотеке.

person axel22    schedule 12.10.2012

Parallel требует произвольного доступа, а java.lang.Iterable его не предоставляет. Это фундаментальное несоответствие, которое не поможет вам с комфортом преодолеть никакое количество конверсий.

Используя аналогию, не связанную с программированием, вы не можете доставить человека из Австралии в Англию, отправив одного человека из Сингапура в Англию, а другого из Австралии в Сингапур одновременно.

Или в программировании, если вы обрабатываете поток данных в реальном времени, вы не можете распараллелить его, обрабатывая данные с этого момента одновременно с данными, полученными пять минут назад, без добавления задержки.

Вам понадобится что-то, что обеспечивает хотя бы некоторый произвольный доступ, например java.util.List.listIterator (Int) вместо Iterable.

person Ricky Clarkson    schedule 12.10.2012
comment
Я предполагаю, что каждый вызов для получения следующего элемента (т.е. Iterable.iterator (). Next ()) выполнялся внутри потока. - person Dan Gravell; 12.10.2012