kotlin asyn c вызовы выполняются последовательно, если они не вызваны с помощью GobalScope. - PullRequest
1 голос
/ 27 марта 2020

хорошо, поэтому у меня есть метод контроллера, который должен сделать кучу soap вызовов внешней службы, каждая из которых довольно тяжелая. Я пытаюсь сделать это в parralel, чтобы сэкономить время, но если я не создаю вызовы async из GlobalScope, отсроченные решаются в последовательности. Позвольте мне показать вам.

, выполнив следующий код

@ResponseBody
@GetMapping(path = ["/buildSoapCall"])
fun searchStations(): String = runBlocking {

    var travels: List<Travel> = service.getTravels().take(500)
    val deferred = travels
            .map {
                async() {
                    print("START")
                    val result = service.executeSoapCall(it)
                    print("END")
                    result
                }
            }
    println("Finished deferred")
    val callResults = deferred.awaitAll()
    println("Finished Awaiting")

    ""
}

, получите следующее консольное сообщение:

Finished deferred
START-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-END.....

- напечатано executeSoapCall

Как видите, отложенные вызовы вызываются последовательно.

Но если я использую GlobalScope, например:

@ResponseBody
@GetMapping(path = ["/buildSoapCall"])
fun searchStations(): String = runBlocking {

    var travels: List<Travel> = service.getTravels().take(500)
    val deferred = travels
            .map {
                GlobalScope.async() {
                    print("START")
                    val result = service.executeSoapCall(it)
                    print("END")
                    result
                }
            }
    println("Finished deferred")
    val callResults = deferred.awaitAll()
    println("Finished Awaiting")

    ""
}

Я получаю следующее консольное сообщение :

Finished Treating 
STARTSTARTSTARTSTARTSTARTSTARTSTARTSTARTSTARTSTARTSTARTFinished deferred
START-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART--ENDENDSTARTSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-ENDSTART-END...START-END-END-END-END-END-END-END-END-END-END-END-ENDFinished Awaiting

, показывающий, что все Отложенные запускаются параллельно. Кроме того, время лечения значительно короче.

Я не совсем понимаю, почему у меня такое поведение.

1 Ответ

1 голос
/ 28 марта 2020

Ваш звонок на service.executeSoapCall блокирует поток runBlocking, на котором работает сопрограмма. Вам нужно каждый раз запускать async сопрограмму в другом потоке, чтобы получить параллельное поведение. Вы можете добиться этого, используя пул потоков, например, Dispatchers.IO:

...
async(Dispatchers.IO) {
    print("START")
    val result = service.executeSoapCall(it)
    print("END")
    result
}
...

или создавая новый поток при каждом вызове:

...
async(newSingleThreadContext("MyThread")) {
    print("START")
    val result = service.executeSoapCall(it)
    print("END")
    result
}
...

GlobalScope работает, потому что он использует ThreadPool по умолчанию, но вы должны избегать его использования. Вы можете прочитать эту статью Роман Елизаров об этом топи c.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...