2010-01-18 3 views
3

Несмотря на приближающуюся стандартную среду fork/join java 7, я создаю вспомогательный метод, который имеет небольшой вес в синтаксисе для того, чтобы клиент мог запускать код параллельно. Вот простой метод, иллюстрирующий идею.Небольшой вес Scala fork присоединяется к синтаксису

import actors.Futures 

object ForkTest2 { 



    def main(args: Array[String]) { 
    test1 
    test2 
    } 



    def test1 { 
    val (a, b, c) =fork({ 
     Thread.sleep(500) 
     println("inside fx1 ",+System.currentTimeMillis) 
     true 
    }, { 
     Thread.sleep(1000) 
     println("inside fx2 ",+System.currentTimeMillis) 
     "stringResult" 
    }, { 
     Thread.sleep(1500) 
     println("inside fx3 ",+System.currentTimeMillis) 
     1 
    }) 

    println(b, a, c) 
    true 
    } 

    def test2 { 
    val results = forkAll({ 
    () => 
       Thread.sleep(500) 
       println("inside fx1 ",+System.currentTimeMillis) 
       true 
    }, { 
    () => 
       Thread.sleep(1000) 
       println("inside fx2 ",+System.currentTimeMillis) 
       "stringResult" 
    }, { 
    () => 
       Thread.sleep(1500) 
       println("inside fx3 ",+System.currentTimeMillis) 
       1 
    }, { 
    () => 
       Thread.sleep(2000) 
       println("inside fx4 ",+System.currentTimeMillis) 
       1.023 
    }) 

    println(results) 
    true 
    } 

    val tenMinutes = 1000 * 60 * 10 

    def fork[A, B, C](
      fx1: => A, 
      fx2: => B, 
      fx3: => C 
     ) = { 
    val re1 = Futures.future(fx1) 
    val re2 = Futures.future(fx2) 
    val re3 = Futures.future(fx3) 
    //default wait 10 minutes 
    val result = Futures.awaitAll(tenMinutes, re1, re2, re3) 
    (
      result(0).asInstanceOf[Option[A]], 
      result(1).asInstanceOf[Option[B]], 
      result(2).asInstanceOf[Option[C]] 

      ) 
    } 

    type fxAny =() => Any 

    def forkAll(
      fx1: fxAny* 
     ): List[Any] = { 
    val results = fx1.toList.map {fx: fxAny => Futures.future(fx())} 
    Futures.awaitAll(tenMinutes, results: _*) 
    } 
} 

образца из пут

(inside fx1 ,1263804802301) 
(inside fx2 ,1263804802801) 
(inside fx3 ,1263804803301) 
(Some(stringResult),Some(true),Some(1)) 
(inside fx1 ,1263804803818) 
(inside fx2 ,1263804804318) 
(inside fx3 ,1263804804818) 
(inside fx4 ,1263804805318) 
List(Some(true), Some(stringResult), Some(1), Some(1.023)) 

тест 1 показан типа типа безопасного возвращения

тест 2 иллюстрирует произвольный входной аргумент

Я надеюсь объединить метод два теста поэтому клиентский код может запускать произвольную функцию параллельно с типом безопасного типа типа.

Еще об аргументах произвольных функций является:

Я думаю, что линия

type fxAny =() => Any 

должен быть действительно код, как

type fxAny = => Any 

, но лестница компилятор не позволит мне Сделай так.

Любая помощь ценится.

ответ

4

Эрик Torreborre написал в ссылке обеспечивается @retronym:

trait LazyParameters { 
    /** transform a value to a zero-arg function returning that value */ 
    implicit def toLazyParameter[T](value: =>T) = new LazyParameter(() => value) 
    /** class holding a value to be evaluated lazily */ 
    class LazyParameter[T](value:()=>T) { 
    lazy val v = value() 
    def apply() = v 
    } 
} 

Вот LazyParameter версия теста:

object ForkTest2 extends LazyParameters { 

...

def forkAll(fx1: LazyParameter[Any]*): List[Any] = { 
    val results = fx1.toList.map { 
    fx: LazyParameter[Any] => Futures.future(fx.apply())} 
    Futures.awaitAll(tenMinutes, results: _*) 
} 

Редактировать: Как вы заметили, неявное оценивает параметр по имени и не переносить задержку оценки. Почему бы просто не использовать слово future? Я лично считаю, что это делает код более удобочитаемым.

import actors.Futures 
import actors.Futures.future 
import actors.Future 

...

def test2 { 
    val results = forkAll(
    future { 
     Thread.sleep(500) 
     println("inside fx1 ",+System.currentTimeMillis) 
     true 
    }, 
    future { 
     Thread.sleep(1000) 
     println("inside fx2 ",+System.currentTimeMillis) 
     "stringResult" 
    }, 
    future { 
     Thread.sleep(1500) 
     println("inside fx3 ",+System.currentTimeMillis) 
     1 
    }, 
    future { 
     Thread.sleep(2000) 
     println("inside fx4 ",+System.currentTimeMillis) 
     1.023 
    }) 

    println(results) 
    true 
} 

...

def forkAll(futures: Future[Any]*): List[Any] = { 
    println("forkAll") 
    Futures.awaitAll(tenMinutes, futures: _*) 
} 
+0

Вы можете определить это еще короче: неявное защиту anyToFun0 [T] (т: => T): (() => T) =() => т (Http://stackoverflow.com/questions/1826145/how-to-write-a-lazy-variable-argument-version-of-orelse/1826794#1826794). Проблема в том, что вы не будете слишком осторожны. Вы должны определить функцию или ленивый val, который будет оцениваться. –

+0

неявная функция заставит fx быть ранней оценкой и вызвана. Клиент должен явно вызвать преобразование типа для предотвращения ранней оценки – laiBilly

0

Реализация образца для тех, кто заинтересован,

Для случая использования, что с помощью нескольких функций аргумента, может быть просто определить список вилки функции с различным количеством аргументов (следуя идею в определении кортежа) и наслаждаться типобезопасен тип возвращаемого

object ForkTest4 extends LazyParameters { 
    def main(args: Array[String]) { 
    test4 
    } 

    def test4 { 
    println("Begin test 4") 
    //Without the explicit call to type conversion would cause early evaluation 
    // val result4 = forkAll({ 
    val result4 = forkAll(l { 
     Thread.sleep(500) 
     println("inside fx4 ", +System.currentTimeMillis) 
     true 
    }) 
    println(result4) 
    true 
    } 

    val tenMinutes = 1000 * 60 * 10 

    def forkAll(fx1: (() => Any)*): List[Any] = { 

    val results = fx1.toList.map { 

     fx: (() => Any) => { 

     val result = Futures.future(fx.apply()) 

     result 
     } 
    } 
    Futures.awaitAll(tenMinutes, results: _*) 
    } 

    def l[T](t: => T): (() => T) =() => t 

    implicit def implicitLazy[T](t: => T): (() => T) =() => t 
}