Вызов функции дважды двумя сопрограммами одновременно - PullRequest
1 голос
/ 10 февраля 2020

Как запустить функцию дважды с помощью двух сопрограмм одновременно? Я пытался с этим кодом:

import kotlinx.coroutines.*

fun main() = runBlocking<Unit> {
    launch {
        calculate("first")
    }
    launch {
        calculate("second")
    }
}

fun calculate(name: String) {
    var value = 0
    for (x in 1..1_000){
        value += 1
        if(x % 100 == 0){
            println("calculating $x for $name")
        }
    }
}

, но вторая сопрограмма ждет, пока первая сопрограмма не выйдет из функции, чтобы запустить ее!

Как мне сделать такую ​​вещь?

Ответы [ 3 ]

1 голос
/ 10 февраля 2020

Диспетчер сопрограмм не может переходить из одной подпрограммы в другую в любом месте вашего кода (как это делают потоки). Весь неподдерживающий (блокирующий) код в сопрограмме вызывается сразу, и только когда сопрограмма приостановлена ​​, диспетчер может позволить другой сопрограмме выполнять свою работу в том же потоке.

Это означает, что ваша функция calculate должна приостановить вашу сопрограмму в некоторых точках - для вашего случая вы должны вызывать функцию приостановки yield(), например, после каждой итерации l oop. Эта функция возвращает поток сопрограммного диспетчера для выполнения другим сопрограммам.

suspend fun calculate(name: String) {
    var value = 0
    for (x in 1..1_000){
        value += 1
        if(x % 100 == 0){
            println("calculating $x for $name")
        }
        yield()
    }
}
0 голосов
/ 10 февраля 2020

Поскольку код, который вы хотите распараллелить, не приостанавливается, у вас нет веских причин использовать сопрограммы. В основном вы используете весь механизм сопрограмм, просто чтобы отправить задание в пул потоков, и заставляете вызывающего пользователя установить sh область сопрограмм.

Вместо этого вы можете просто отправить задачи исполнителю, лежащему в основе IO диспетчер:

fun main() {
    Dispatchers.IO.asExecutor().apply {
        execute { calculate("first") }
        execute { calculate("second") }
    }
}
0 голосов
/ 10 февраля 2020

runBlocking использует событие l oop в качестве значения по умолчанию для диспетчера сопрограмм. С событием l oop одновременно может выполняться только одна сопрограмма в потоке события.

Вы можете указать любой другой диспетчер, который использует пул потоков, например, Dispatchers.Default, для одновременного запуска сопрограмм.

fun main() = runBlocking<Unit>(Dispatchers.Default) {
    launch {
        calculate("first")
    }
    launch {
        calculate("second")
    }
}
...