suspend function: qué es, sintaxis y funcionamiento en corutinas

Autor: IT Sectr Publicado: 2026-06-22 Tiempo de lectura: 9 min

Suspend function es una función con el modificador suspend que puede pausar su ejecución sin bloquear un hilo y reanudarse más tarde en la misma corutina. Según JetBrains Kotlin Docs, 2025, las funciones suspend son un bloque fundamental de las corutinas, proporcionando asincronía sin callbacks. Cada función suspend se compila en una máquina de estados basada en Continuation, permitiendo una gestión eficiente de los puntos de suspensión.

Puntos clave

  • Suspend — palabra clave de Kotlin que marca una función como pausable (asíncrona)
  • Continuation — parámetro oculto que el compilador añade a cada función suspend para guardar el estado
  • Puntos de suspensión — lugares donde se llaman otras funciones suspend, donde una corutina puede detenerse sin bloquear
  • Máquina de estados — representación interna de una función suspend, donde cada punto de suspensión es un estado separado
  • Llamada solo desde corutina — las funciones suspend solo pueden llamarse desde otra función suspend o desde launch/async

¿Qué es una suspend function en Kotlin?

Suspend function es una función declarada con la palabra clave suspend que puede pausar la ejecución en uno o más puntos sin bloquear el hilo. Cada llamada a una función suspend dentro de otra función suspend es un punto de suspensión potencial.

kotlin
suspend fun fetchUserData(): User {
    val response = httpClient.get("/user")
    return parser.parse(response)
}

El compilador de Kotlin traduce dicha función en una máquina de estados. Cada punto de suspensión (una llamada a otra función suspend) se convierte en un estado (label). El hilo actual se libera entre estados, y cuando la operación esperada se completa, la ejecución se reanuda desde el siguiente estado.

Historia

Las funciones suspend aparecieron en Kotlin 1.3 (2018) junto con las corutinas como característica experimental y se volvieron estables en Kotlin 1.5 (2021). Antes de eso, la asincronía en Kotlin/Java se lograba mediante callbacks, RxJava y CompletableFuture. Las funciones suspend ofrecieron una alternativa con sintaxis lineal y gestión automática de hilos.

Cómo funcionan las funciones suspend: Continuation y máquina de estados

Comprender el funcionamiento interno de las funciones suspend es la clave para trabajar correctamente con corutinas. A diferencia de las funciones normales, cada función suspend se compila en una clase con la interfaz Continuation.

Continuation — el parámetro oculto

El compilador de Kotlin añade un parámetro de tipo Continuation al final de cada lista de parámetros de una función suspend. Continuation contiene:

  • context — CoroutineContext (dispatcher, job, elementos del contexto)
  • resumeWith — método para reanudar la ejecución con un resultado o excepción
  • label — índice del estado actual en la máquina de estados

Ejemplo de máquina de estados

Supongamos que tenemos una función suspend con dos llamadas a otras funciones suspend:

kotlin
suspend fun process() {
    val a = stepOne()
    val b = stepTwo(a)
    println(b)
}

El compilador la transforma en una máquina de estados con etiquetas:

kotlin
// Simplified generated code representation
fun process(cont: Continuation<Unit>): Any? {
    val cont = cont as ProcessContinuation
    when (cont.label) {
        0 -> {
            cont.label = 1
            if (stepOne(cont) == COROUTINE_SUSPENDED) return COROUTINE_SUSPENDED
        }
        1 -> {
            cont.label = 2
            val a = cont.result as TypeA
            if (stepTwo(a, cont) == COROUTINE_SUSPENDED) return COROUTINE_SUSPENDED
        }
        2 -> {
            println(cont.result)
            Unit
        }
    }
}

Observación clave: si la función devuelve COROUTINE_SUSPENDED, el hilo actual se libera. Cuando la operación asíncrona se completa, se llama a Continuation.resumeWith y la máquina de estados continúa desde la siguiente etiqueta.

Sintaxis de las funciones suspend: declaración e invocación

Declarar una función suspend no es diferente de una función normal, excepto por la palabra clave suspend antes de fun. Solo hay una restricción: una función suspend solo puede llamarse desde una corutina u otra función suspend.

Declaración básica

kotlin
suspend fun delayAndReturn(ms: Long): String {
    delay(ms)
    return "Done after ${ms}ms"
}

En este ejemplo, delay también es una función suspend que suspende la corutina durante el número especificado de milisegundos sin bloquear el hilo. Después de la pausa, la ejecución se reanuda.

Llamada desde una corutina

kotlin
fun main() = runBlocking {
    val result = delayAndReturn(1000)
    println(result)
}

runBlocking crea un puente entre el mundo normal y las corutinas. Dentro de la lambda, se puede llamar a cualquier función suspend.

Lambdas suspend y tipos funcionales

Kotlin admite versiones suspend de tipos funcionales — suspend () -> T y suspend (A) -> B. Esto permite pasar lambdas asíncronas a funciones de orden superior:

kotlin
suspend fun  withRetry(
    retries: Int = 3,
    block: suspend () -> T
): T {
    repeat(retries - 1) {
        try { return block() }
        catch (_: Exception) { delay(100) }
    }
    return block()
}

La función withRetry recibe una lambda suspend y reintenta su ejecución en caso de error. Este es un patrón típico para solicitudes de red con reintentos.

Diferencias entre funciones suspend y funciones normales

Las diferencias entre funciones suspend y normales van más allá de simplemente añadir un modificador. Veamos las diferencias clave.

CaracterísticaFunción normalFunción suspend
Hilo de ejecuciónBloquea el hilo hasta que terminaPuede liberar el hilo y reanudarse después
Parámetros del compiladorSolo los parámetros especificadosContinuation implícito al final
Llamada desde función normalNo
PilaPila física del hiloMáquina de estados en heap + pila física entre puntos
Valor de retornoValor directoValor o COROUTINE_SUSPENDED
RendimientoSobrecarga mínima~unos nanosegundos por máquina de estados (Kotlin 1.9+)

Por qué las funciones suspend no pueden llamarse desde funciones normales

Una función normal no tiene un Continuation — no tiene dónde guardar el estado ni con qué reanudar la ejecución. Si necesitas llamar a una función suspend desde una normal, usa runBlocking (para pruebas) o CoroutineScope.launch (para producción teniendo en cuenta el ciclo de vida).

Ejemplos de funciones suspend en Android

Veamos tres escenarios reales de uso de funciones suspend en aplicaciones Android con Kotlin.

Ejemplo 1: Room DAO con consultas suspend

Room admite funciones suspend directamente — la consulta se ejecuta en un hilo en segundo plano automáticamente:

kotlin
@Dao
interface UserDao {
    @Query("SELECT * FROM users WHERE id = :id")
    suspend fun getUser(id: Int): User?

    @Insert
    suspend fun insertUser(user: User)
}

Room internamente usa Dispatchers.IO para ejecutar la consulta, y el resultado se devuelve en el dispatcher donde se llamó a la función suspend.

Ejemplo 2: Composición de funciones suspend para carga de pantalla

kotlin
class ProfileViewModel : ViewModel() {
    private val repo = ProfileRepository()

    fun loadProfile(id: String) {
        viewModelScope.launch {
            val profile = repo.getProfile(id)
            _profile.value = profile
        }
    }
}

ViewModelScope.launch crea una corutina, dentro de la cual se llama a la función suspend getProfile. Después de obtener el resultado, la interfaz se actualiza en el hilo principal.

Ejemplo 3: Pasos asíncronos secuenciales

kotlin
suspend fun placeOrder(cart: Cart): OrderResult {
    val validated = validateCart(cart)
    val payment = processPayment(validated)
    val receipt = sendReceipt(payment)
    return receipt
}

Tres funciones suspend se ejecutan secuencialmente. En cada paso, la corutina puede suspenderse sin bloquear el hilo. Si algún paso lanza una excepción, los pasos restantes no se ejecutan, protegiendo contra estados de pedido incorrectos.

Errores comunes al trabajar con funciones suspend

Incluso los desarrolladores experimentados de Kotlin cometen errores al diseñar funciones suspend. Veamos los más comunes.

Error 1: Llamadas bloqueantes dentro de suspend

Una función suspend no hace que el código sea automáticamente asíncrono. Thread.sleep(), InputStream.read() y otras llamadas bloqueantes seguirán bloqueando el hilo. Usa withContext(Dispatchers.IO) para envolver operaciones bloqueantes.

Error 2: Crear funciones suspend sin necesidad

Si una función no llama a otras funciones suspend ni realiza operaciones asíncronas — el modificador suspend es redundante. Añade sobrecarga a la máquina de estados y restringe el contexto de llamada. Haz que una función sea suspend solo cuando realmente se suspenda.

Error 3: Ignorar CancellationException

Cuando se cancela una corutina, las funciones suspend lanzan CancellationException. No la captures sin pensar — le quitas al código llamante la capacidad de completar correctamente la cancelación. Si necesitas realizar una operación de finalización, usa un bloque finally y NonCancellable.

kotlin
suspend fun safeOperation() {
    try {
        doWork()
    } finally {
        withContext(NonCancellable) {
            cleanup()
        }
    }
}

El bloque finally siempre se ejecuta, incluso en la cancelación, y NonCancellable garantiza que la limpieza no se interrumpa.

Error 4: Llamar a funciones suspend desde callbacks

No puedes llamar a una función suspend directamente desde un callback sin crear una corutina. Usa suspendCoroutine o suspendCancellableCoroutine para adaptar el estilo de callback a las corutinas.

Preguntas frecuentes

¿Puede una función suspend no tener puntos de suspensión?

Sí, técnicamente una función suspend puede no llamar a otras funciones suspend. El compilador creará una máquina de estados con un solo estado (label 0). Sin embargo, no hay ningún beneficio práctico en tal función — se ejecuta como una normal pero con sobrecarga. No uses suspend innecesariamente.

¿Cómo depurar funciones suspend?

Kotlin proporciona kotlinx-coroutines-debug — una biblioteca con DebugProbes y herramientas de trazado de corutinas. En Android Studio a partir de Arctic Fox, hay una pestaña Coroutines incorporada en el Depurador que muestra las corutinas activas, su estado y los puntos de suspensión.

¿Afecta el número de puntos de suspensión al rendimiento?

Cada punto de suspensión crea un nuevo estado en la máquina de estados. Para la mayoría de las aplicaciones, la sobrecarga de un punto es de unos pocos nanosegundos (Kotlin 1.9+). Solo con decenas de miles de puntos en un bucle deberías considerar combinar operaciones o usar sequence/flow.

¿En qué se diferencia una función suspend de async/await en otros lenguajes?

En Kotlin, suspend es un modificador de tipo de función, no un marcador de valor de retorno (como async en C#). Cualquier función suspend puede tener cualquier parámetro y tipo de retorno, y su llamada sintácticamente no difiere de una llamada a una función normal — no hay un operador await en el lugar de la llamada.

¿Cómo convertir una función callback a suspend?

Usa suspendCancellableCoroutine para la adaptación. Dentro, registras un callback que llama a continuation.resume(), y devuelves un token de cancelación si el callback admite cancelación de suscripción. Este es el patrón estándar para envolver APIs antiguas de Android.

Resumen

  • Suspend function — función con el modificador suspend que puede pausar la ejecución sin bloquear un hilo mediante el mecanismo Continuation
  • Máquina de estados — representación interna de una función suspend en bytecode de Kotlin, donde cada punto de suspensión es un estado separado con una etiqueta
  • Continuation — parámetro oculto que contiene el contexto de la corutina y el método resumeWith para reanudar la ejecución
  • Llamada solo desde corutina — las funciones suspend no son accesibles desde funciones normales sin runBlocking o CoroutineScope
  • Operaciones bloqueantes dentro de suspend requieren withContext(Dispatchers.IO) — de lo contrario el hilo se bloquea
  • Room y Retrofit admiten funciones suspend de forma nativa, gestionando automáticamente los hilos en segundo plano
  • CancellationException — maneja la cancelación mediante finally + NonCancellable, no captures CancellationException sin pensar

Desarrollaremos una aplicación móvil llave en mano

IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.

Discutir el proyecto

Lea también