Существует ли стандартная функция Scala для запуска блока с таймаутом? - PullRequest
8 голосов
/ 03 июня 2011

Мне нужно позвонить в службу, которая может дать или не вернуть своевременные результаты.Я хотел бы иметь возможность написать

val result = runWithTimeout(5000, valReturnedOnTimeout) { service.fetch }

Есть ли стандартная функция, которая будет выполнять эту работу - как Таймаут Руби ?

Ответы [ 6 ]

7 голосов
/ 03 июня 2011

С учетом других ответов - в отсутствие какой-либо стандартной библиотечной функции я пошел по пути Futures.

  import scala.concurrent.ExecutionContext.Implicits.global
  import scala.concurrent._
  import scala.concurrent.duration._

  def runWithTimeout[T](timeoutMs: Long)(f: => T) : Option[T] = {
    Await.result(Future(f), timeoutMs milliseconds).asInstanceOf[Option[T]]
  }

  def runWithTimeout[T](timeoutMs: Long, default: T)(f: => T) : T = {
    runWithTimeout(timeoutMs)(f).getOrElse(default)
  }

Так что

  @Test def test {
    runWithTimeout(50) { "result" } should equal (Some("result"))
    runWithTimeout(50) { Thread.sleep(100); "result" } should equal (None)
    runWithTimeout(50, "no result") { "result" } should equal ("result")
    runWithTimeout(50, "no result") { Thread.sleep(100); "result" } should equal("no result")
  }

Буду благодарен за любые отзывы о том, хороший ли это стиль Scala!

5 голосов
/ 03 июня 2011

Вы можете использовать будущее

import scala.actors.Futures._  

val myfuture = 
    future {
     Thread.sleep(5000)
     println("<future>")
     "future "
 }

 awaitAll(300,myfuture ) foreach println _   

Но взгляните также на Автоматический выключатель для Scala , который является реализацией шаблона автоматического выключателя .В основном это позволяет вам контролировать время ожидания и то, что должно произойти в случае сбоя при доступе к внешнему ресурсу

Использование выглядит так в Scala (из файла readme):

. . .
addCircuitBreaker("test", CircuitBreakerConfiguration(timeout=100,failureThreshold=10))
. . .


class Test extends UsingCircuitBreaker {
  def myMethodWorkingFine = {
    withCircuitBreaker("test") {
      . . .
    }
  }

  def myMethodDoingWrong = {
    withCircuitBreaker("test") {
      require(false,"FUBAR!!!")
    }
  }
}
2 голосов
/ 04 июня 2011

Что-то, что еще не было упомянуто, - awaitEither , метод объекта Futures пакета актеров. awaitEither возвращает результат из первой пары фьючерсов для завершения, так что, например, можно использовать что-то вроде этого:

awaitEither(future{task}, alarm(timeoutPeriod))

и затем оделись в соответствии с предложенным методом:

def runWithTimeout[T](timeoutPeriod: Int, timeoutValue: T)(task: => T) = {
  awaitEither(future{task}, alarm(timeoutPeriod)) match {case () => timeoutValue case x => x}
}

alarm возвращает Единицу, которая присваивается значению типа Any, поэтому awaitEither возвращает что-то, с чем можно сопоставить шаблон.

2 голосов
/ 03 июня 2011

Might Futures и его alarm делают свое дело?

1 голос
/ 03 июня 2011

Вы можете запустить его в новом потоке, а затем дождаться его завершения с помощью Thread.join. Если вы передадите параметр для присоединения, он будет ждать не более многих миллисекунд.

val t = new Thread {
  override def run() {
    //...
  }
}
t.start()
t.join(5000)
0 голосов
/ 30 июля 2018

Пост выше

  import scala.concurrent.ExecutionContext.Implicits.global   import
 scala.concurrent._   import scala.concurrent.duration._

   def runWithTimeout[T](timeoutMs: Long)(f: => T) : Option[T] = {
     Await.result(Future(f), timeoutMs milliseconds).asInstanceOf[Option[T]]   }

   def runWithTimeout[T](timeoutMs: Long, default: T)(f: => T) : T = {
     runWithTimeout(timeoutMs)(f).getOrElse(default)   }

у меня не работал в Scala 2.11.

У меня работает следующая модифицированная версия:

  def runWithTimeout[T](timeout: Long)(f: => T): Option[T] = {
    Option.apply(Await.result(Future(f), timeout seconds))
  }
...