2017-01-29 2 views
2

Я новичок в Scala, я пытаюсь создать большую карту из IndexedSeq, я нашел упоминание о SO о том, что создание карты функционального стиля намного медленнее, чем настоятельный Java-стиль, решил проверить его сам. До сих пор я узнал, что не только функциональный код Scala работает медленнее, но и очень важно. Что я делаю неправильно, почему мой код Scala в несколько раз медленнее? На моем домашнем компьютере он работает в 220 мс. (Java) и 460 мс. (Scala)Почему мой фрагмент создания карты стиля Scala медленнее, чем Java?

Scala version

private val testSize: Int = 1000000 

    val seq: IndexedSeq[Int] = for (i <- 0 until testSize) yield Random.nextInt() 

    val warmupMapt0 = System.nanoTime() 

    var warmupMap: mutable.HashMap[Int, Int] = new mutable.HashMap[Int, Int] 
    warmupMap.sizeHint(testSize) 
    for (i <- 0 until testSize) warmupMap.put(i, seq(i)) 

    val t0 = System.nanoTime() 
    var map: mutable.HashMap[Int, Int] = new mutable.HashMap[Int, Int] 
    map.sizeHint(testSize) 
    for (i <- 0 until testSize) map.put(i, seq(i)) 
    println((System.nanoTime() - t0)/ 1000000 + " ms.") 

Java version

private static final int TEST_SIZE = 1_000_000; 

public static void main(String[] args) { 

    int[] ar = new int[TEST_SIZE]; 
    Random random = new Random(); 
    for (int i = 0; i < TEST_SIZE; i++) { 
     ar[i] = random.nextInt(); 
    } 

    Map<Integer, Integer> warmupMap = new HashMap<>(TEST_SIZE); 
    for (int i = 0; i < TEST_SIZE; i++) { 
     warmupMap.put(i, ar[i]); 
    } 

    Map<Integer, Integer> map = new HashMap<>(TEST_SIZE); 
    long t0 = System.nanoTime(); 
    for (int i = 0; i < TEST_SIZE; i++) { 
     map.put(i, ar[i]); 
    } 
    System.out.println((System.nanoTime() - t0)/1_000_000 + " ms."); 
} 
+0

Это может помочь вам http://stackoverflow.com/questions/9799085/scala-perf-why-is-this-scala-app-30x-slower-than-the-equivalent-java-app?rq=1 –

+0

@ Jean-BaptisteYunès Да, я видел это, поэтому я добавил val warmupMapt0 = System.nanoTime() перед тем, как начать, а также попытался запустить его с консоли, но это не помогло. – MaxNevermind

+0

Не могли бы вы добавить свои временные результаты? – maasg

ответ

0

Это, вероятно, for понимание. В Scala они работают совсем по-другому, чем for в Java, и создают код, который JVM не может оптимизировать достаточно хорошо. См. http://www.scalablescala.com/roller/scala/entry/why_is_using_for_foreach или http://downloads.typesafe.com/website/presentations/ScalaDaysSF2015/T2_Rytz_Backend_Optimizer.pdf (начиная со слайда 37). Вы можете обойти это, используя петлю while или библиотеку макросов, такую ​​как http://scala-blitz.github.io/, https://github.com/non/spire или https://github.com/nativelibs4java/scalaxy-streams.

+0

Не большая разница с циклом while http://ideone.com/h8gF0E – MaxNevermind

3

Я думаю, что одним из источников проблемы является использование IndexedSeq. Это по умолчанию реализуется Vector, который обычно представляет собой интеллектуальную коллекцию, но в вашем случае он добавляет довольно большой постоянный фактор для создания «массива» чисел и доступа к ним по индексу. Если вы хотите, чтобы ваш код более эквивалентен Java аналог следующего код будет ответ:

val ar = new Array(TestSize) 
for (i <- 0 until TestSize) ar(i) = Random.next() 

Я где-то читал о Еогеаспе петель оптимизации, не может найти, где, в основном, учитывая достаточное количество прогрева работает цикл по каждому элементу должен иметь схожую эффективность по сравнению с циклом while, данная переданная функция может быть встроена.

Редактировать

Код может быть еще более упрощен:

val ar = Array.fill(TestSize)(Random.next()) 

Предложено Алексей Романов в комментарии.

+0

Я попробую, когда вернусь домой, мой офисный ноутбук покажет еще большую разницу ~ 100 мс \ 1000 мс, я думаю, мне нужно что-то прочитать о бенчмаркинге, Не ожидайте такого разнообразия результатов на разных аппаратных средствах и средах. – MaxNevermind

+1

За последнее предложение: к сожалению, нет (или еще нет). См. Http://downloads.typesafe.com/website/presentations/ScalaDaysSF2015/T2_Rytz_Backend_Optimizer.pdf, начиная с слайда 37. Новый оптимизатор в 2.12 позволяет встраивать его, но не делает по умолчанию (и разминка для него не имеет значения). –

+0

Вы также можете упростить 'val ar = Array.fill (TestSize) (Random.next())'. –

Смежные вопросы