DEV Community

GoyesDev
GoyesDev

Posted on

SC #12: DiscardingTaskGroup

DiscardingTaskGroup es un TaskGroup que descarta los resultados de sus subtareas.

Se dice que hace un uso eficiente de la memoria, puesto que no es necesario retener a las subtareas para hacer next().

Aunque las tareas no retornen valores, el grupo sí puede hacerlo.

let numberOfTasksAdded = await withDiscardingTaskGroup(returning: Int.self) { group in
  group.addTask {
    print("Long running task completed without a return value")
  }
  return 1
}
print("El DiscardingTaskGroup agregó \(numberOfTasksAdded) tarea(s).")
Enter fullscreen mode Exit fullscreen mode

Un DiscardingTaskGroup espera automáticamente a todas las subtareas. No hay manera explícita de esperarlas como usar next().

Cancelar un DiscardingTaskGroup

Se puede cancelar un DiscardingTaskGroup con group.cancelAll(). Cancelar el grupo, propaga la cancelación de forma recursiva a las subtareas.

¿Cuándo usar un DiscardingTaskGroup?

Se usa un DiscardingTaskGroup cuando se requiere ejecutar varias tareas asíncronas de forma concurrente y no importan sus valores de retorno.

Manejo de errores

Como es posible explícitamente esperar a que termine cada subtarea de forma individual (i.e. next()), no es posible capturar y volver a lanzar el error de la subtarea:

// ThrowingTaskGroup, este patrón no es aplicable a ThrowingDiscardingTaskGroup
try await withThrowingTaskGroup(of: Void.self) { group in
  group.addTask { try boom() }
  try await group.next() // re-throws "boom"
}
Enter fullscreen mode Exit fullscreen mode

Como DiscardingTaskgroup no tiene acceso a next(), un DiscardingTaskGroup se cancela implícitamente cuando uno de los subtareas arroja un error.

El primer error capturado será arrojado de nuevo por withThrowingDiscardingTaskGroup:

try await withThrowingDiscardingTaskGroup { group in
  group.addTask {
    /// Se arrojará el primer error capturado
    throw Error.exampleErrorOne
  }
  group.addTask {
    try await Task.sleep(for: .seconds(1))
    // Esta línea nunca va a alcanzarse porque 
    // exampleErrorOne se arroja primero y cancela el grupo
    print("About to throw error two")
    throw Error.exampleErrorTwo
  }
}
Enter fullscreen mode Exit fullscreen mode

Ignorando errores

En algunos escenarios, no es necesario cancelar el grupo cuando se cancela una subtarea. En este caso, se puede atrapar el error y retornar dentro de la definición de la tarea.

try await withThrowingDiscardingTaskGroup { group in
  group.addTask {
    do {
      try boom(1)
    } catch is HarmlessError {
      return
    }
  }
  group.addTask {
    try boom(2, after: .seconds(5))
  }
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)