Guía 30 de 53
Tareas paralelas y plazos
Resultados paralelos nombrados, plazos de await y delegación lazy.
En esta página
Resultados paralelos nombrados, plazos de await y delegación lazy.
Resultados paralelos nombrados¶
Las tareas nombradas en parallel producen un record tipado tras la unión estructurada. Cada tarea captura el alcance exterior; las etiquetas no son variables para tareas hermanas. Los fallos cancelan y esperan cooperativamente a las hermanas. Se rechazan resultados transitivamente lineales.
Practica en By Example · Programa fuente
// Feature: typed named results from structured parallel tasks
// Each label names a result field; each RHS captures only the outer scope.
struct User { name: str }
async fn load_user() -> User = User { name: "Ada" }
async fn load_orders() -> [int] = [101, 102]
let user = "outer"
let data = parallel {
user = await load_user()
orders = await load_orders()
captured = user
}
print(data.user.name)
print(data.orders.len())
print(data.captured)
print(user)
// expected:
// Ada
// 2
// outer
// outerEjecuta este ejemplo localmente con la CLI instalada. El playground del navegador no proporciona el scheduler del host.
Plazos de await¶
await tarea within duración devuelve un Result tipado de timeout. Al expirar, el scheduler solicita cancelación y espera la limpieza cooperativa. Una tarea que devuelve Result produce un Result anidado; elige qué capa propagar. El trabajo nativo sin checkpoints no puede interrumpirse por la fuerza.
Practica en By Example · Programa fuente
async fn load() -> int {
sleep 20ms
42
}
fn main() {
let result = await load() within 1s
print(result.unwrap())
}Ejecuta este ejemplo localmente con la CLI instalada. El playground del navegador no proporciona el scheduler del host.
Delegación lazy de generadores¶
yield ... hijo delega un valor cada vez y mantiene el cursor del hijo entre reanudaciones. No materializa un array. Cerrar el generador exterior cierra el hijo activo y ejecuta su limpieza; yield común conserva su comportamiento.
Practica en By Example · Programa fuente
fn* middle()->int{yield 2;yield 3}
fn* values()->int{yield 1;yield ... middle();yield 4}
for value in values(){print(value)}Lectura de una fuente asíncrona¶
for await pide un valor a la vez a la fuente y espera a next() antes de ejecutar el cuerpo del bucle. Nil termina la iteración. El método conocido next() debe devolver Future<T?> o Task<T?>, y la fuente debe implementar core::cleanup::Cleanup. El ejemplo consume una fuente completa e interrumpe otra antes del final; ambas se cierran.
use core::cleanup::Cleanup
struct Events { remaining: int }
impl Events {
async fn next(self) -> int? {
if self.remaining <= 0 { return nil }
let value = self.remaining
self.remaining -= 1
return value
}
}
impl Cleanup for Events {
fn close(self) { print("closed") }
}
let complete = Events { remaining: 3 }
var sum = 0
for await value in complete { sum += value }
assert_eq(sum, 6)
let early = Events { remaining: 5 }
:events for await value in early {
if value == 4 { break :events }
print(value)
}
print(sum)La fuente se adquiere una vez y se cierra al terminar, interrumpir, devolver, fallar o recibir cancelación cooperativa. Los patrones, incluido for await case, examinan el valor esperado. Los arrays síncronos no se convierten en fuentes asíncronas. Ejecute con la CLI; wasm-aot rechaza explícitamente las operaciones del planificador.
Límite del trabajo concurrente¶
parallel(limit: 2) [for id in ids => await load_profile(id)] procesa un array con un máximo de dos trabajos activos y devuelve los resultados en el orden de entrada. El ejemplo cuenta los trabajos activos para comprobar el límite y después verifica una entrada vacía y la copia de los elementos de la fuente.
var active = 0
var peak = 0
async fn load_profile(id: int) -> int {
active += 1
if active > peak { peak = active }
defer { active -= 1 }
sleep 2ms
return id * 10
}
let profiles = parallel(limit: 2) [for id in [1, 2, 3, 4] => await load_profile(id)]
assert_eq(peak, 2)
assert_eq(active, 0)
assert_eq(profiles.len(), 4)
assert_eq(profiles[0], 10)
assert_eq(profiles[3], 40)
print(peak)
print(profiles[0])
print(profiles[3])
let no_ids: [int] = []
let empty = parallel(limit: 4) [for id in no_ids => id]
assert_eq(empty.len(), 0)
// The pool snapshots source items before evaluating any mapper.
let mut ids = [1, 2, 3]
let original = parallel(limit: 1) [for id in ids => { ids[1] = 99; id }]
assert_eq(original[1], 2)
assert_eq(ids[1], 99)El límite entero positivo y la fuente se evalúan una vez, en ese orden. Un grupo fijo de trabajadores toma el siguiente elemento al terminar el actual; no se crea una tarea por entrada. La copia de la fuente protege los elementos pendientes frente a cambios posteriores. Un fallo cancela los otros trabajos y espera la limpieza antes de propagar el error. La concurrencia es cooperativa; los cálculos sin suspensión no reciben threads del sistema. Disponible en VM, nativo y LLVM; wasm-aot informa de la limitación del planificador.
Sigue aprendiendo¶
DOCS / OPINIÓN
¿Esta página dejó alguna pregunta?
Cuéntanos dónde te perdió la explicación. La documentación también forma parte de la experiencia del lenguaje.