Облегченный синтаксис вилки Scala - PullRequest
3 голосов
/ 18 января 2010

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

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

, но компилятор scala не позволяет мне это делать.

Любая помощь приветствуется.

Ответы [ 3 ]

4 голосов
/ 18 января 2010

Эрик Торреборре написал по ссылке, предоставленной @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: _*)
}
2 голосов
/ 18 января 2010

Вы не можете использовать типы вызова по имени в качестве повторяющегося параметра (он же varargs), благодаря этой ошибке: https://lampsvn.epfl.ch/trac/scala/ticket/237

Смотрите недавнее обсуждение здесь: http://old.nabble.com/Lazy-varargs-td27169264.html

0 голосов
/ 18 января 2010

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

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

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