Вопрос 1 : API-запрос все еще будет выполняться на IO-диспетчере, но он заблокирует поток, на котором он работает. Это означает, что никакие другие задачи не могут быть запланированы в этом потоке в ожидании завершения запроса sh. На самом деле нет никакой причины использовать runBlocking
в рабочем коде вообще, потому что:
- Если
makeRequest
уже является блокирующим вызовом, то runBlocking
практически ничего не сделает. - Если бы
makeRequest
был приостановленным вызовом, то runBlocking
сделает код менее эффективным. Он не вернет поток в пул во время ожидания завершения запроса sh.
Является ли makeRequest
блокирующим или неблокирующим вызовом, зависит от клиента, которого вы с помощью. Вот неблокирующий http-клиент, который я могу порекомендовать: https://ktor.io/clients/
Вопрос 2 : я бы использовал Flow
для этой цели. Вы можете думать об этом как о приостановленном варианте Sequence
. Потоки холодные , что означает, что он не будет работать, пока потребитель не запросит его содержимое (в отличие от hot , что означает, что производитель получит pu sh новых значений no важно, хочет ли потребитель этого или нет). Kotlin Flow
имеет оператор под названием buffer
, который можно использовать, чтобы он запрашивал больше страниц, прежде чем он полностью использует предыдущую страницу.
Код может выглядеть очень похоже на то, что у вас уже есть :
suspend fun getAllRowsFromAPI(client: Client): Flow<Row> = flow {
var currentRequest: Request? = client.requestForNextPage()
while(currentRequest != null) {
val rowsInPage = client.makeRequest(currentRequest)
emitAll(rowsInPage.asFlow())
currentRequest = client.requestForNextPage()
}
}.flowOn(Dispatchers.IO)
.buffer(capacity = 1)
Емкость 1 означает, что при обработке более ранней страницы будет сделан только 1 запрос. Вы можете увеличить размер буфера, чтобы сделать больше параллельных запросов. Вы должны проверить этот доклад на KotlinConf 2019, чтобы узнать больше о потоках: https://www.youtube.com/watch?v=tYcqn48SMT8