Мне удалось найти ответ на эти вопросы, хотя есть некоторые вещи, которые я не понимаю.
Почему программа зависает вместо завершения через 1 секунду?
По какой-то причине Executors.newSingleThreadScheduledExecutor()
вызывает зависание. Чтобы решить проблему, мне пришлось использовать Executors.newSingleThreadScheduledExecutor(new Thread(_))
. Похоже, единственное отличие состоит в том, что первая версия эквивалентна Executors.newSingleThreadScheduledExecutor(Executors.defaultThreadFactory())
, хотя ничто в документах не объясняет, почему это так.
Почему мы установить mayInterruptIfRunning = false
? Разве весь смысл отмены заключается в том, чтобы прервать выполнение задачи?
Я должен признать, что не совсем понимаю это. Опять же, документы не особо проясняли этот вопрос. Переключение флага на true
, похоже, не меняет поведения вообще, по крайней мере, в случае прерываний Ctrl-c
.
Является ли это рекомендуемым способом определения ScheduledExecutorService? Я не видел примеров в документах.
Очевидно, нет. Способ, который я придумал, был слабо вдохновлен этим фрагментом из исходного кода эффекта кошки.
Эта программа ждет 1 секунду, а затем возвращает ()
(затем неожиданно виснет). Что если я захочу вернуть что-нибудь еще? Например, скажем, я хотел вернуть строку, результат некоторых длительных вычислений. Как мне извлечь это значение из IO.cancelable
? Кажется, сложность заключается в том, что IO.cancelable
возвращает операцию отмены, а не возвращаемое значение процесса, подлежащего отмене.
Блок IO.cancellable { ... }
возвращает IO[A]
и обратный вызов cb
функция имеет тип Either[Throwable, A] => Unit
. Логически это говорит о том, что все, что вводится в функцию cb
, - это то, что будет возвращено выражением IO.cancellable (в IO
). Таким образом, чтобы вернуть строку "hello"
вместо ()
, мы переписываем delayedTick
:
def delayedTick(d: FiniteDuration)
(implicit sc: ScheduledExecutorService): IO[String] = { // Note IO[String] instead of IO[Unit]
implicit val processRunner: JVMProcessRunner[IO] = new JVMProcessRunner
IO.cancelable[String] { cb => // Note IO.cancelable[String] instead of IO[Unit]
val r = new Runnable {
def run() =
cb(Right("hello")) // Note "hello" instead of ()
}
val f: ScheduledFuture[_] = sc.schedule(r, d.length, d.unit)
IO(f.cancel(true))
}
}