2010-02-03 4 views
4

Я пытаюсь использовать параллельное программирование в Scala. Основанный на this example здесь, в StackOverflow, я сделал программу на основе Problem 1 Project Euler. Я пробую три метода: первый - это простое исполнение, без паралилизма. В поле second используется API java.util.concurrency через исполнителей и вызываемые вызовы. Третий, основанный на странице, упомянутой выше, с использованием scala.Futures. Моя цель - сравнить время выполнения.Параллельная обработка в Scala

Это код:

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)) 
    } 
} 

Таковы результаты:

макс = 10:

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

макс = 100:

  • Одно: (2318,33)
  • бассейн: (2318,31)
  • фьючерсы: (2318,55)

макс = 1000:

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

макс = 10000:

  • Одно: (23331668,144)
  • бассейн: (23331668,544)
  • фьючерсы : ... Я отменил выполнение через 3 минуты

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

ответ

1

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

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

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

1

Предполагаете, вы используете 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 в диапазон, и все будет хорошо.

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