kotlinadvanced

Coroutine Select Expression

Use select expression to await the first result from multiple suspending operations or channels.

kotlin
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
import kotlinx.coroutines.selects.select

fun main() = runBlocking {
    // Select from multiple channels
    val chan1 = Channel<String>()
    val chan2 = Channel<String>()

    launch {
        delay(100)
        chan1.send("From channel 1")
    }
    launch {
        delay(50)
        chan2.send("From channel 2")
    }

    // First to arrive wins
    val fastest = select {
        chan1.onReceive { it }
        chan2.onReceive { it }
    }
    println("Fastest: $fastest") // From channel 2

    // Select from multiple async operations
    suspend fun fetchFromApi1(): String {
        delay(200); return "API 1 result"
    }
    suspend fun fetchFromApi2(): String {
        delay(100); return "API 2 result"
    }

    val result = coroutineScope {
        val api1 = async { fetchFromApi1() }
        val api2 = async { fetchFromApi2() }
        select {
            api1.onAwait { it }
            api2.onAwait { it }
        }
    }
    println("First API: $result")

    // Select with timeout
    val slowChannel = Channel<String>()
    launch {
        delay(5000) // very slow
        slowChannel.send("Slow result")
    }

    val timedResult = select {
        slowChannel.onReceive { it }
        onTimeout(1000) { "Timed out" }
    }
    println("Timed: $timedResult") // Timed out

    // Fan-in with select
    val producers = (1..3).map { id ->
        produce {
            repeat(3) {
                delay((50..150).random().toLong())
                send("Producer-$id: item-$it")
            }
        }
    }

    repeat(9) {
        val item = select {
            producers.forEach { producer ->
                producer.onReceive { it }
            }
        }
        println("Received: $item")
    }

    println("Done")
}

Use Cases

  • Racing multiple async operations
  • Timeout handling for slow operations
  • Priority-based channel consumption

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.