Есть ли стандартная функция Scala для запуска блока с таймаутом?

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

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

есть ли стандартная функция, которая будет делать эту работу - как Руби автоотключение?

6 ответов


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

  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!


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

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

Might фьючерсы и alarm делать трюк?


то, что еще не было упомянуто, это 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}
}

сигнализация возвращает единицу, которая назначается val типа Any so awaitEither возвращает что-то, что может быть сопоставлено шаблону против.


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

val t = new Thread {
  override def run() {
    //...
  }
}
t.start()
t.join(5000)

пост выше

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