Решение вытекает прямо из вопроса. Сначала мы разработаем функцию приостановки для этой задачи. Давайте посмотрим наши требования:
если некоторые задания занимают больше времени, чем время ожидания ... без отмены работ, которые все еще выполняются.
Это означает, что запускаемые нами задания должны быть автономными (не дочерними), поэтому мы будем отказываться от структурированного параллелизма и будем использовать GlobalScope
для их запуска, собирая вручную все задания. Мы используем async
сопрограмма строитель, потому что мы планируем собрать их результаты типа R
позже:
val jobs: List<Deferred<R>> = List(numberOfJobs) {
GlobalScope.async { /* our code that produces R */ }
}
после запуска заданий мне нужно подождать, пока они все завершат свою задачу, ИЛИ истечь заданный тайм-аут, в зависимости от того, что наступит раньше.
Давайте подождем их всех и сделаем это с таймаутом:
withTimeoutOrNull(timeoutMillis) { jobs.joinAll() }
Мы используем joinAll
(в отличие от awaitAll
), чтобы избежать исключения в случае сбоя одного из заданий, и withTimeoutOrNull
, чтобы избежать исключения по таймауту.
моя основная функция должна активизироваться по истечении времени ожидания, проверить, какие задания закончились вовремя (если есть), а какие еще работают
jobs.map { deferred -> /* ... inspect results */ }
В основном коде (который не является сопрограммой) ...
Поскольку наш основной код не является сопрограммой, он должен ждать блокирующим образом, поэтому мы соединяем код, который мы написали, используя runBlocking
. Собираем все вместе:
fun awaitResultsWithTimeoutBlocking(
timeoutMillis: Long,
numberOfJobs: Int
) = runBlocking {
val jobs: List<Deferred<R>> = List(numberOfJobs) {
GlobalScope.async { /* our code that produces R */ }
}
withTimeoutOrNull(timeoutMillis) { jobs.joinAll() }
jobs.map { deferred -> /* ... inspect results */ }
}
P.S. Я бы не рекомендовал развертывать такого рода решения в любой серьезной производственной среде, так как запуск фоновых заданий (утечка) после истечения времени ожидания будет неизменно сильно кусать вас в дальнейшем. Делайте это, только если вы полностью понимаете все недостатки и риски такого подхода.