LINUX.ORG.RU

Автоматическое распараллеливание в Scala

 , ,


0

3

Изучаю скалу. Поскольку язык весьма декларативный, то логично ожидать от него автоматической векторизации всего что только можно и исполнения его на многочисленных ядрах современных процов. Такая фича действительно есть и как её можно увидеть?

Для примера взял такой код:

object ImpossiblePuzzle extends App {
  val range = 1000
  type XY = (Int, Int)
  val step0 = for {
    x <- 1 to range
    y <- 1 to range
    if 1 < x && x < y && x + y < range
  } yield (x, y)
 
  def sum(xy: XY) = xy._1 + xy._2
  def prod(xy: XY) = xy._1 * xy._2
  def sumEq(xy: XY) = step0 filter { sum(_) == sum(xy) }
  def prodEq(xy: XY) = step0 filter { prod(_) == prod(xy) }
 
  val step2 = step0 filter { sumEq(_) forall { prodEq(_).size != 1 }}
  val step3 = step2 filter { prodEq(_).intersect(step2).size == 1 }
  val step4 = step3 filter { sumEq(_).intersect(step3).size == 1 }
  println(step4)
}

Отсюда: http://en.wikipedia.org/wiki/Sum_and_Product_Puzzle#Scala_code Но параллельного исполнения (в REPL) как-то не заметно. Как его получить?

★★★★★

Последнее исправление: CYB3R (всего исправлений: 1)
Ответ на: комментарий от BattleCoder

Не, OpenCL ручками я и без скалы могу. Зачем она мне нужна, если ручками?

asaw ★★★★★
() автор топика
Ответ на: комментарий от stevejobs

Ну, я так понимаю, для начала сам код нужно адаптировать к тому, что написано по первой ссылке? Как вот этот вот вектор

val step0 = for {
    x <- 1 to range
    y <- 1 to range
    if 1 < x && x < y && x + y < range
  } yield (x, y)
сделать «параллельным»?

asaw ★★★★★
() автор топика
Ответ на: комментарий от BattleCoder

Да, как ни удивительно замена 1 to range на (1 to range).par действительно всё распараллеливает (правда, пока не понятно есть ли в данном случае от этого какой-то приход кроме загрузки всех ядер). Но тогда не понятно почему оно по умолчанию не так...

asaw ★★★★★
() автор топика
Ответ на: комментарий от asaw

Насколько я ничего не понимаю, этот for развернется во что-то типа (1 to range) flatMap (_ => 1 to range) filter { ... }, поэтому все, что тут можно распараллелить - это первую строчку. В некоторых случаях, возможно, имеет смысл сначала в один поток построить сам список (x, y), потом ему сделать .par, и дальнейшие преобразования уже делать параллельно.

ovk48 ★★★
()
Ответ на: комментарий от asaw

Но тогда не понятно почему оно по умолчанию не так...

Потому что параллельные коллекции появились в стандартной библиотеке сильно позже обычных.

ovk48 ★★★
()
Ответ на: комментарий от asaw

равда, пока не понятно есть ли в данном случае от этого какой-то приход кроме загрузки всех ядер

для range = 500 на моём лэптопе так вот получается:

$ time ./ImpossiblePuzzlePar.sh 
Starting computing... 
ParVector((4,13))
done computing.

real	1m43.854s
user	11m28.772s
sys	0m2.510s

$ time ./ImpossiblePuzzle.sh 
Starting computing... 
Vector((4,13))
done computing.

real	6m27.945s
user	6m27.562s
sys	0m0.559s
asaw ★★★★★
() автор топика
Ответ на: комментарий от asaw

Вы неправильно время измеряете. ;) Тут стоит учитывать, что JVM довольно медленно запускается, нужно какое-то время на «разогрев».

BattleCoder ★★★★★
()
Ответ на: комментарий от asaw

Да. Тут скорее всего больше вредят издержки на создание forkjoinpool и потоков в нём.

В любом случае прирост есть, я вижу - всё круто же.

BattleCoder ★★★★★
()

Используй метод par для коллекций.

LongLiveUbuntu ★★★★★
()
Ответ на: комментарий от asaw

А если головоломку побольше сделать? Чтобы не на 6 минут, а на 60 минут, например?

BattleCoder ★★★★★
()
Ответ на: комментарий от asaw

Ещё какая штука. По умолчанию используется некий глобальный implicit fork join pool, если не ошибаюсь. Можно подставить свой. Можно покрутить настройки (количество потоков, к примеру). Там ни разу не факт, что их 8 штук создаётся. И может быть прирост будет больше, если их будет больше восьми.

BattleCoder ★★★★★
()
Ответ на: комментарий от asaw

Но тогда не понятно почему оно по умолчанию не так...

Потому что нельзя автоматически распараллеливать код в котором могут быть side эффекты.

maxcom ★★★★★
()
Ответ на: комментарий от maxcom

Откуда они там могут быть, если никаких соглашений по поводу последовательности обработки чего-либо и так нет?

asaw ★★★★★
() автор топика
Ответ на: комментарий от asaw

Пользователь может работать с нетредобезопасными объектами в лямбдах которые передаются в map и т.п.

maxcom ★★★★★
()
Ответ на: комментарий от maxcom

Тогда компилятор должен просто люто ругаться. Иначе это какое-то недо-ФП получается.

asaw ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.