Saltar al contenido

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
//   outer

Ejecuta 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.

By Example

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.

By Example

Sigue aprendiendo

Documentación · Practica en By Example

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.

Índice global

Encuentra tu camino por Zolo

Prueba una idea

Empieza aquí

9 resultados

9 resultados

enespt-br