(k, v) }.toMapЗатем я использую эту карту для создания своего объекта: case class MyObject(val attribute1: Str" />

Скала неизменяемая Карта медленная

java performance scala functional-programming bigdata

711 просмотра

1 ответ

У меня есть кусок кода, когда я создаю карту, как:

 val map = gtfLineArr(8).split(";").map(_ split "\"").collect { case Array(k, v) => (k, v) }.toMap

Затем я использую эту карту для создания своего объекта:

case class MyObject(val attribute1: String, val attribute2: Map[String:String]) 

Я читаю миллионы строк и конвертирую в MyObjects с помощью итератора. подобно

MyObject("1", map)

Когда я делаю это очень медленно, более 1 часа для 2 000 000 записей.

Я удаляю карту из создания объекта, но все же делаю процесс разделения (раздел 1):

val map = gtfLineArr(8).split(";").map(_ split "\"").collect { case Array(k, v) => (k, v) }.toMap
MyObject("1", null)

И процесс запуска скрипта занимает не более 1 мин. за 2'000'000 миллионов записей.

Я сделал некоторое профилирование и похоже, что когда объект создается, присваивание между val mapкартой объекта замедляет процесс. Чего мне не хватает?

Обновление, чтобы лучше объяснить проблему:

Если вы видите мой код для объяснения моего собственного итерации по 2000000 строк, преобразовывающих каждую строку во внутренний объект, для итерации я делаю:

it.map(cretateNewObject).toList

этот итератор перебирает все строки и конвертирует их в мои объекты с помощью функции createNewObject.

Это действительно очень быстро, особенно с использованием большой памяти, как сказал dk14. Проблема с производительностью у меня внутри

`crateNewObject(val line:String)` 

эта функция создает объект

`class MyObject(val attribute1:String, val attribute2:Map[String, String])` 

моя функция взять линию и сделать первым

`val attributeArr = line.split("\t")` 

первая запись атрибута массива - attribute1 моего объекта, а второй атрибут -

`val map = attributeArr(8).split(";").map(_ split "\"").collect { case Array(k, v) => (k, v) }.toMap` 

если я только печатаю количество элементов в карте, программы заканчиваются через 2 минуты, если я передаю карту моей новой строке объекта, MyObject(attribute1, map)программа действительно медленная.

Автор: ypriverol Источник Размещён: 08.11.2019 11:11

Ответы (1)


3 плюса

Решение

(0 to 2000000).toListи (0 to 2000000).map(x => x -> x).toMapиметь аналогичную производительность, если вы предоставите им достаточно памяти (я пробовал -Xmx4G - 4 гигабайта). toMapреализация - это много о клонировании, поэтому много памяти «выделяется» / «освобождается». Итак, в случае голодания памяти ГК становится сверхактивным.

Когда я попытался запустить (0 to 2000000).toListс 128Mb - это заняло несколько секунд, но (0 to 2000000).map(x => x -> x).toMapзаняло не менее 2 минут с активностью 10% GC (VisualVM), и умерло с нехваткой памяти.

Однако, когда я попробовал, -Xmx4Gоба были довольно быстры.


PS Что toMapозначает постоянное добавление элемента в дерево префиксов, поэтому он должен многократно клонировать ( Array.copy) для каждого элемента: https://github.com/scala/scala/blob/99a82be91cbb85239f70508f6695c6b21fd3558c/src/library/scala/collection/ immutable / HashMap.scala # L321 .

Таким образом, toMapвыполняется многократно (2000000 раз) updated0, что, в свою очередь, Array.copyдовольно часто, что требует большого выделения памяти, что (в случае нехватки памяти) заставляет GC переходить в MarkAndSweep (медленная сборка мусора) большую часть времени (как насколько я вижу из jconsole).


Решение: будь то увеличение памяти ( -Xmx/ -XmsJVM-параметров) или если вам нужны более сложные операции с вашим набором данных, используйте что-то вроде Apache Spark (или любую пакетно-ориентированную структуру сокращения карт) для обработки ваших данных распределенным способом.

Автор: dk14 Размещён: 20.08.2016 01:17
Вопросы из категории :
32x32