Есть ли стандартная функция 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!!!")
}
}
}
то, что еще не было упомянуто, это 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))
}