Параллельная обработка в Scala - PullRequest
4 голосов
/ 03 февраля 2010

Я пытаюсь использовать параллельное программирование в Scala. На основании этот пример здесь, в StackOverflow, я сделал программу на основе Задача 1 Project Euler. Я пробую три метода: первый - простое выполнение без паралелизма. второй использует java.util.concurrency API через Executors и Callables. Третий, основанный на упомянутой выше странице, использует scala.Futures. Моя цель - сравнить время выполнения.

Это код:

package sandbox

import java.util.concurrent._
import scala.actors._

object TestPool {

  def eval(n: Int): Boolean = (n % 3 == 0) || (n % 5 == 0)

  def runSingle(max: Int): Int = (1 until max).filter(eval(_)).foldLeft(0)(_ + _)

  def runPool(max: Int): Int = {

    def getCallable(i: Int): Callable[Boolean] = new Callable[Boolean] { def call = eval(i) }

    val pool = Executors.newFixedThreadPool(5)
    val result = (1 until max).filter(i => pool.submit(getCallable(i)).get).foldLeft(0)(_ + _)
    pool.shutdown
    pool.awaitTermination(Math.MAX_LONG, TimeUnit.SECONDS)

    result
  }

  def runFutures(max: Int): Int = (1 until max).filter(i => Futures.future(eval(i)).apply).foldLeft(0)(_ + _)

  /**
   * f is the function to be runned. it returns a Tuple2 containing the sum and the 
   * execution time.
   */
  def test(max: Int, f: Int => Int): (Int, Long) = {
    val t0 = System.currentTimeMillis
    val result = f(max)
    val deltaT = System.currentTimeMillis - t0

    (result, deltaT)
  }


  def main(args : Array[String]) : Unit = {
    val max = 10000

    println("Single : " + test(max, runSingle))
    println("Pool   : " + test(max, runPool))
    println("Futures: " + test(max, runFutures))
  }
}

Вот результаты:

max = 10:

  • Одноместный: (23,31)
  • Бассейн: (23,16)
  • Фьючерсы: (23,31)

max = 100:

  • Одноместный: (2318,33)
  • Бассейн: (2318,31)
  • Фьючерсы: (2318,55)

max = 1000:

  • Single: (233168,42)
  • Бассейн: (233168,111)
  • Фьючерсы: (233168,364)

max = 10000:

  • Single: (23331668,144)
  • Бассейн: (23331668,544)
  • Фьючерсы: ... Я отменил исполнение через 3 минуты

Очевидно, я не мог правильно использовать API параллелизма из Java и Scala. Поэтому я спрашиваю: Где моя ошибка? Какова наиболее подходящая форма использования параллелизма? А про Scala Actors? Можно ли их использовать?

Ответы [ 2 ]

1 голос
/ 03 февраля 2010

Я предполагаю, что вы используете Scala 2.7. По сути, filter и map для Range (результат 1 until max) не являются строгими, то есть будут вычисляться по требованию и вычисляться каждый раз при попытке доступа к его результатам.

Попробуйте это, например:

val y = (1 to 10).filter{x => println("Filtering "+x); x % 2 == 0}.map{x => println("Mapping "+x); x * 2}
println(y(0))
println(y(1))
println(y(2))
println(y(0))

В любом случае, результат заключается в том, что ваши параллельные компоненты работают последовательно. Добавьте .force в диапазон, и все будет хорошо.

1 голос
/ 03 февраля 2010

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

Сколько ядер у вашей машины?Если у вас есть только одно ядро, то вы должны ожидать, что время будет линейно увеличиваться в зависимости от выполняемой работы.Как выглядит использование вашего процессора во время прогонов?Числа повторяемы?

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...