Scala - сравнение производительности агрегата против foldLeft
Насколько я понимаю, /: то же самое, что и foldLeft, а также то, что агрегат является более быстрой версией foldLeft, если список преобразуется в параллельную коллекцию с использованием 'par'. Если я прав, почему следующий код показывает, что:/ и foldLeft быстрее, чем агрегат, используемый с 'par' в списке.
Я вычисляю сумму элементов и количество элементов большого списка и сохраняю результат в кортеже [Double,Double].
//initial tuple2 (sum,count)
val tsc:Tuple2[Double,Double] = Tuple2(0.0,0.0)
//create a large list
val largeList = List.tabulate(500000)(n=>n*n)
//note time
val time1 = System.currentTimeMillis
//using aggregate without par
largeList.aggregate(tsc) ((tsc,elem) => (tsc._1+elem, tsc._2+1), (tsc1, tsc2)=>((tsc1._1+tsc2._1), (tsc1._2+tsc2._2)))
//note time
val time2 = System.currentTimeMillis
//use aggregate with par
largeList.par.aggregate(tsc) ((tsc,elem) => (tsc._1+elem, tsc._2+1), (tsc1, tsc2)=>((tsc1._1+tsc2._1), (tsc1._2+tsc2._2)))
//note time
val time3 = System.currentTimeMillis
//use /:
(tsc /: largeList)((tsc,elem)=>(tsc._1+elem, tsc._2+1))
//note time
val time4 = System.currentTimeMillis
//use foldLeft
largeList.foldLeft(tsc)((tsc,elem)=>(tsc._1+elem, tsc._2+1))
//note time
val time5 = System.currentTimeMillis
//calcualte time difference
println ("Time without par (millisecond)"+(time2-time1))
println ("Time with par (millisecond)"+(time3-time2))
println ("Time with /: (millisecond)"+(time4-time3))
println ("Time with FoldLeft (millisecond)"+(time5-time4)
Я получил следующий результат
результат на 1-м пробеге
Time without par (millisecond)1198
Time with par (millisecond)1479
Time with /: (millisecond)626
Time with FoldLeft (millisecond)661
результат на 2-м пробеге
Time without par (millisecond)703
Time with par (millisecond)581
Time with /: (millisecond)435
Time with FoldLeft (millisecond)423
Я запускаю это в Windows 10 с помощью CMD. /: и FoldLeft кажутся похожими по производительности и значительно лучше, чем совокупные. Агрегирование с номиналом на самом деле занимало больше времени в 1-й серии. Может ли это быть проблемой из-за того, что 'cmd' (консоль) в окне не может использовать многопоточность (только предположения здесь)
1 ответ
Несколько проблем. Ваш набор данных действительно довольно мал (поэтому затраты на распараллеливание и управление потоками значительны). С помощью List
означает, что шаг объединения вашего агрегата равен O(N) - это, по-видимому, наиболее значимый фактор после увеличения размера набора данных.
Переключение на Vector
и используя Вектор в 10 раз больше, я получаю:
Time without par (millisecond)271
Time with par (millisecond)297
Time with /: (millisecond)216
Time with FoldLeft (millisecond)274
что менее драматично. Я просто делал один прогон на листе Scala, поэтому видел много изменений в этих цифрах
(У меня только двухъядерная система, поэтому накладные расходы на распараллеливание значительны по сравнению с выигрышами, кажется)