¿Qué hace Task.sleep() y cómo se usa?
Task.sleep(for:tolerance:clock:) suspende la tarea en curso por el tiempo determinado.
Si la tarea es cancelada antes de que la suspensión termine, entonces se arroja un error de tipo CancellationError.
El hilo NO se bloquea, así que mientras que la tarea está suspendida, el hilo se puede ocupar para ejecutar tareas de más baja prioridad.
try await Task.sleep(for: .seconds(3))
Casos de uso de Task.sleep():
NOTA: Recordar envolver con do catch porque puede arrojar un error.
- Rebote (Debounce) en la entrada de un usuario:
func search(_ query: String) {
currentSearchTask?.cancel()
currentSearchTask = Task {
do {
try await Task.sleep(for: .milliseconds(500))
searchResults = Self.items.filter {
$0.lowercased().contains(query.lowercased())
}
} catch {
print("Se canceló la tarea")
}
}
}
Preguntar periódicamente por el estado de un API con AsyncSequences
Limitar número de peticiones web
Retrasos artificiales
¿Qué hace Task.yield() y cómo se usa?
Task.yield() suspende la tarea en curso y permite que otras tareas se ejecuten.
Una tarea larga se puede suspender a sí misma voluntariamente para que otras tareas se ejecuten por un rato. Sin embargo, si la tarea en cuestión es la de más alta prioridad, entonces será reanudada de inmediato.
Una analogía de esto sería estar en una fila de un supermercado con el carro vacío y se deja pasar a una persona más vieja que uno, embarazada o discapacitada.
Para no monopolizar un executor, si tengo una tarea que hace un trabajo muy largo y pesado, puedo suspenderla y ceder el turno. Un ejemplo podría ser el caso donde tenga que procesar miles de imágenes. En cada iteración del loop puedo dar espacio a otras tareas para que se ejecuten entre iteraciones.
for image in thousandsOfImages {
process(image)
await Task.yield() // "oye, si alguien más necesita correr, adelante"
}
Casos de uso de Task.yield():
Task.yield() se puede usar para dejar que el código de una prueba automatizada avance, hasta que los resultados estén disponibles para su validación.
func testIsLoading() async {
/// Se ejcutan en un executor serial para tratar de ejecutar todas las tareas de forma serial
await withMainSerialExecutor {
let model = NumberFactModel(getFact: {
/// Para la tarea en curso y deja que las otras tareas continúen primero
await Task.yield()
return "\($0) is a good number."
})
let task = Task { await model.getFactButtonTapped() }
/// Para la prueba para que `getFactButtonTapped()` sea llamado.
await Task.yield()
XCTAssertEqual(model.isLoading, true)
XCTAssertEqual(model.fact, nil)
/// Espera hasta que la tarea retorne su valor
await task.value
XCTAssertEqual(model.isLoading, false)
XCTAssertEqual(model.fact, "0 is a good number.")
}
}
Diferencias clave entre ambos:
- Tanto
yield()comosleep()no bloquean el hilo. -
sleep()suspende una tarea por un tiempo determinado y permite que otras tareas de menor prioridad se ejecuten.yield()suspende una tarea y cede la ejecución a otras tarea con la misma o mayor prioridad.
RECITE - Responde estas preguntas de memoria:
- ¿
Task.sleep()bloquea el hilo subyacente? ¿Qué implica eso? - ¿Qué error lanza
Task.sleep()si la tarea es cancelada? - ¿Qué pasa con
Task.yield()si la tarea actual ya es la de mayor prioridad en el sistema? - ¿Cuál es el caso de uso más común de
Task.sleep()mencionado en el artículo? - ¿Para qué usa el autor
Task.yield()principalmente en su experiencia? - ¿Cuál de los dos métodos tiene una duración de suspensión fija? ¿Y cuál indeterminada?
- ¿Cuál de los dos es interrumpible mediante cancelación?
REVIEW — Revisión y conexión
¿En qué se parece y en qué se diferencia Task.sleep() de un sleep() tradicional?
¿Por qué Task.yield() podría no tener ningún efecto en ciertos contextos?
Pensando en tu propio código, ¿hay algún lugar donde podrías aplicar el patrón de debounce con Task.sleep()?
¿Qué relación tiene este artículo con el concepto de prioridad de tareas visto anteriormente?
Top comments (0)