Как добиться неблокирования с сопрограммами - PullRequest
0 голосов
/ 04 января 2019

Я пытаюсь добиться сопрограмм блокировки ввода-вывода (kotlin) таким образом, чтобы получать больше сетевых вызовов, чем потоков. Понятно, как использовать сопрограммы таким образом, чтобы не блокировать основной поток, однако в конечном итоге каждая сопрограмма запускается в протекторе, и сеть вызывает блокировку этого потока (для сравнения, использование NodeJS позволяет повторно использовать рабочий поток, в то время как другие запросы жду ответа, чтобы вернуться).

Мой вариант использования заключается в том, что для каждого входящего запроса мне нужно сделать 2-3 независимых внешних вызова, объединить ответ и вернуться. Делать это последовательно - пустая трата времени. Параллельное выполнение этого потребует от моего сервиса выполнения примерно в 2-3 раза большего количества входящих потоков (что составляет около 1 КБ потоков только для ожидания ввода-вывода).

Во многих примерах процедур используется delay, что позволяет одновременно использовать потоки для нескольких процедур. Однако, используя реальный вариант использования сетевых вызовов, я не могу этого достичь.

Чего мне не хватает? Как я могу приостановить сопрограмму, пока внешняя служба не ответит?

Например, этот пример работает только на 5 потоках, но повторно использует потоки более 1000 вызовов, поэтому все заканчивается в течение ~ 100 мс (каждая операция составляет 100 мс)

val myPool = Executors.newFixedThreadPool(5).asCoroutineDispatcher()
runBlocking {
  (1..1000).forEach {
    launch(myPool) {
      delay(100)
    }
  }
}

В противоположность этому, на самом деле выполняется только 5 одновременных вызовов в 5 потоках, и переход к следующему выполняется только после завершения. Я хочу, чтобы все вызовы выполнялись "параллельно", используя возможность отправки запроса в ожидании ответа - так же, как это делается в NodeJS :

val restTemplate = RestTemplate()
val myPool = Executors.newFixedThreadPool(5).asCoroutineDispatcher()
runBlocking {
  (1..1000).forEach {
    launch(myPool) {
      restTemplate.getForObject("http://myTest.com", String::class.java) // Say it takes 100ms to response
    }
  }
}

1 Ответ

0 голосов
/ 07 января 2019

Сопрограммы Kotlin не волшебство, которое превращает ваши блокирующие сетевые операции в неблокирующие. Они позволяют использовать только асинхронную сетевую реализацию без лишних затрат и обратных вызовов.

Итак, чтобы продолжить,

  • Шаг 1. Найти асинхронную библиотеку REST
  • Шаг 2. Напишите немного кода Kotlin, чтобы связать нативный API библиотеки на основе обратного вызова или будущего с сопрограммами Kotlin.
...