Существуют ли операторы asyncAll и / или awaitAll для сопрограмм Kotlin?

У меня есть коллекция, и я хочу выполнить некоторые операции со всеми ее элементами асинхронно в Kotlin.

Я легко могу сделать это с помощью двух операций с картой:

suspend fun collectionAsync() = coroutineScope {

    val list = listOf("one", "two", "three")

    list.map { async { callRemoteService(it) } }.map { it.await() }.forEach { println(it) }
}

suspend fun callRemoteService(input: String): String
{
    delay(1000)
    return "response for $input"
}

Я хотел бы иметь что-то вроде этого:

asyncAll(list, ::callRemoteService).awaitAll()

Я, наверное, смог бы реализовать это с помощью функций расширения. Мне просто интересно, есть ли более идиоматический способ сделать это.

ИЗМЕНИТЬ: я обнаружил, что awaitAll уже существует. Теперь мне просто нужен asyncAll.

list.map { async { callRemoteService(it) } }.awaitAll().forEach { println(it) }

EDIT2: я написал свою реализацию asyncAll:

fun <T, V> CoroutineScope.asyncAll(
    items: Iterable<T>,
    function: suspend (T) -> V
): List<Deferred<V>>
{
    return items.map { async { function.invoke(it) } }
}

Итак, теперь у меня есть это, что выглядит довольно хорошо:

asyncAll(list) { callRemoteService(it) }.awaitAll()

Теперь мне просто интересно, существует ли это уже сейчас :)

EDIT3: если подумать, это могло бы выглядеть даже лучше:

list.asyncAll { callRemoteService(it) }.awaitAll()

У меня просто проблемы с реализацией. Поскольку у меня уже есть приемник, который является итеративным, я не уверен, как передать область действия программы:

fun <T, V> Iterable<T>.asyncAll(
    function: (T) -> V
): List<Deferred<V>>
{
    return this.map { async { function.invoke(it) } }
}

person Martin Tarjányi    schedule 13.04.2019    source источник
comment
Более чем удобочитаемость, использование в качестве расширения области более очевидно, проверьте явный параллелизм и структурированный параллелизм.   -  person Vairavan    schedule 13.04.2019


Ответы (1)


Наконец-то я получил желаемое. Мне нужна эта функция расширения:

suspend fun <T, V> Iterable<T>.asyncAll(coroutine: suspend (T) -> V): Iterable<V> = coroutineScope {
    [email protected] { async { coroutine(it) } }.awaitAll()
}

и я могу использовать это так:

list.asyncAll { callRemoteService(it) }.forEach { println(it) }

Я не уверен насчет наименования. Это тоже могло быть asyncMap.

person Martin Tarjányi    schedule 10.04.2021
comment
ИМХО, это очень элегантно. Теперь я должен понять, как это работает! :) - person Luca Hofmann; 29.05.2021