Почему именно будущее.firstCompletedOf не вызывать обратный вызов по таймауту?
Я делаю упражнения из обучения параллельному программированию в Scala.
Для вопроса упражнения в комментарии кода.
- программа печатает правильный вывод содержимого HTML для правильного URL и таймаута достаточно.
- программа печатает "ошибка произошла"для правильного URL и низкого таймаута.
Однако для недопустимого URL "ошибка произошла" не печатается. В чем проблема с приведенным ниже кодом?
/*
* Implement a command-line program that asks the user to input a URL of some website,
* and displays the HTML of that website. Between the time that the user hits ENTER and
* the time that the HTML is retrieved, the program should repetitively print a . to the
* standard output every 50 milliseconds, with a two seconds timeout. Use only futures
* and promises, and avoid the synchronization primitives from the previous chapters.
* You may reuse the timeout method defined in this chapter.
*/
object Excersices extends App {
val timer = new Timer()
def timeout(t: Long = 1000): Future[Unit] = {
val p = Promise[Unit]
val timer = new Timer(true)
timer.schedule(new TimerTask() {
override def run() = {
p success ()
timer cancel()
}
}, t)
p future
}
def printDot = println(".")
val taskOfPrintingDot = new TimerTask {
override def run() = printDot
}
println("Enter a URL")
val lines = io.Source.stdin.getLines()
val url = if (lines hasNext) Some(lines next) else None
timer.schedule(taskOfPrintingDot, 0L, 50.millisecond.toMillis)
val timeOut2Sec = timeout(2.second.toMillis)
val htmlContents = Future {
url map { x =>
blocking {
Source fromURL (x) mkString
}
}
}
Future.firstCompletedOf(Seq(timeOut2Sec, htmlContents)) map { x =>
timer cancel ()
x match {
case Some(x) =>
println(x)
case _ =>
println("Error occured")
}
}
Thread sleep 5000
}
2 ответа:
Как сказал @Gábor Bakos исключение производит
Failure
, который не обрабатывается картой:val fut = Future { Some(Source fromURL ("hhhttp://google.com")) } scala> fut map { x => println(x) } //nothing printed res12: scala.concurrent.Future[Unit] = scala.concurrent.impl.Promise$DefaultPromise@5e025724
Для обработки отказа-используйте метод
recover
:scala> fut recover { case failure => None } map { x => println(x) } None res13: scala.concurrent.Future[Unit] = scala.concurrent.impl.Promise$DefaultPromise@578afc83
В вашем контексте это что-то вроде:
Future.firstCompletedOf(Seq(timeOut2Sec, htmlContents)) recover {case x => println("Error:" + x); None} map { x => ...}
Полный код после использования recover, как советует @dk14:
object Exercises extends App { val timer = new Timer() def timeout(t: Long = 1000): Future[Unit] = { val p = Promise[Unit] val timer = new Timer(true) timer.schedule(new TimerTask() { override def run() = { p success () timer cancel () } }, t) p future } def printDot = println(".") val taskOfPrintingDot = new TimerTask { override def run() = { printDot } } println("Enter a URL") val lines = io.Source.stdin.getLines() val url = if (lines hasNext) Some(lines next) else None timer.schedule(taskOfPrintingDot, 0L, 50.millisecond.toMillis) val timeOut2Sec = timeout(2.second.toMillis) val htmlContents = Future { url map { x => blocking { Source fromURL (x) mkString } } } Future.firstCompletedOf(Seq(timeOut2Sec, htmlContents)) .recover { case x => println("Error:" + x); None } .map { x => timer cancel () x match { case Some(x) => println(x) case _ => println("Timeout occurred") } } Thread sleep 5000 }