Corrutinas y Tareas
*******************

Esta sección describe las API de asyncio de alto nivel para trabajar
con corrutinas y tareas.

* Corrutinas

* Esperables

* Ejecutando un programa asyncio

* Creando Tareas

* Durmiendo

* Ejecutando Tareas Concurrentemente

* Protección contra Cancelación

* Tiempo agotado

* Esperando Primitivas

* Planificación Desde Otros Hilos

* Introspección

* Objeto Task

* Corrutinas basadas en generadores


Corrutinas
==========

*Coroutines* declarado con la sintaxis async/await es la forma
preferida de escribir aplicaciones asyncio. Por ejemplo, el siguiente
fragmento de código (requiere Python 3.7+) imprime "hola", espera 1
segundo y, a continuación, imprime "mundo":

   >>> import asyncio

   >>> async def main():
   ...     print('hello')
   ...     await asyncio.sleep(1)
   ...     print('world')

   >>> asyncio.run(main())
   hello
   world

Tenga en cuenta que simplemente llamando a una corrutina no programará
para que se ejecute:

   >>> main()
   <coroutine object main at 0x1053bb7c8>

Para ejecutar realmente una corrutina, asyncio proporciona tres
mecanismos principales:

* La función "asyncio.run()" para ejecutar la función de punto de
  entrada de nivel superior "main()" (consulte el ejemplo anterior.)

* Esperando en una corrutina. El siguiente fragmento de código
  imprimirá "hola" después de esperar 1 segundo y luego imprimirá
  "mundo" después de esperar *otros* 2 segundos:

     import asyncio
     import time

     async def say_after(delay, what):
         await asyncio.sleep(delay)
         print(what)

     async def main():
         print(f"started at {time.strftime('%X')}")

         await say_after(1, 'hello')
         await say_after(2, 'world')

         print(f"finished at {time.strftime('%X')}")

     asyncio.run(main())

  Salida esperada:

     started at 17:13:52
     hello
     world
     finished at 17:13:55

* La función "asyncio.create_task()" para ejecutar corrutinas
  concurrentemente como asyncio "Tasks".

  Modifiquemos el ejemplo anterior y ejecutemos dos corrutinas
  "say_after" *concurrentemente*:

     async def main():
         task1 = asyncio.create_task(
             say_after(1, 'hello'))

         task2 = asyncio.create_task(
             say_after(2, 'world'))

         print(f"started at {time.strftime('%X')}")

         # Wait until both tasks are completed (should take
         # around 2 seconds.)
         await task1
         await task2

         print(f"finished at {time.strftime('%X')}")

  Tenga en cuenta que la salida esperada ahora muestra que el
  fragmento de código se ejecuta 1 segundo más rápido que antes:

     started at 17:14:32
     hello
     world
     finished at 17:14:34


Esperables
==========

Decimos que un objeto es un objeto **esperable** si se puede utilizar
en una expresión "await". Muchas API de asyncio están diseñadas para
aceptar los valores esperables.

Hay tres tipos principales de objetos *esperables*: **corrutinas**,
**Tareas** y **Futuros**.

-[ Corrutinas ]-

Las corrutinas de Python son *esperables* y por lo tanto se pueden
esperar de otras corrutinas:

   import asyncio

   async def nested():
       return 42

   async def main():
       # Nothing happens if we just call "nested()".
       # A coroutine object is created but not awaited,
       # so it *won't run at all*.
       nested()

       # Let's do it differently now and await it:
       print(await nested())  # will print "42".

   asyncio.run(main())

Importante:

  En esta documentación se puede utilizar el término "corrutina" para
  dos conceptos estrechamente relacionados:

  * una *función corrutina*: una función "async def";

  * un *objeto corrutina*: un objeto retornado llamando a una *función
    corrutina*.

asyncio también es compatible con corrutinas heredadas generator-
based.

-[ Tareas ]-

*Las tareas* se utilizan para programar corrutinas *concurrentemente*.

Cuando una corrutina se envuelve en una *Tarea* con funciones como
"asyncio.create_task()" la corrutina se programa automáticamente para
ejecutarse pronto:

   import asyncio

   async def nested():
       return 42

   async def main():
       # Schedule nested() to run soon concurrently
       # with "main()".
       task = asyncio.create_task(nested())

       # "task" can now be used to cancel "nested()", or
       # can simply be awaited to wait until it is complete:
       await task

   asyncio.run(main())

-[ Futuros ]-

Un "Future" es un objeto esperable especial de **bajo-nivel** que
representa un **resultado eventual** de una operación asíncrona.

Cuando un objeto Future es *esperado* significa que la corrutina
esperará hasta que el Future se resuelva en algún otro lugar.

Los objetos Future de asyncio son necesarios para permitir que el
código basado en retro llamada se use con async/await.

Normalmente , **no es necesario** crear objetos Future en el código de
nivel de aplicación.

Los objetos Future, a veces expuestos por bibliotecas y algunas API de
asyncio, pueden ser esperados:

   async def main():
       await function_that_returns_a_future_object()

       # this is also valid:
       await asyncio.gather(
           function_that_returns_a_future_object(),
           some_python_coroutine()
       )

Un buen ejemplo de una función de bajo nivel que retorna un objeto
Future es "loop.run_in_executor()".


Ejecutando un programa asyncio
==============================

asyncio.run(coro, *, debug=False)

   Ejecuta la *coroutine* *coro* y retornando el resultado.

   Esta función ejecuta la corrutina pasada, encargándose de
   administrar el bucle de eventos asyncio y *finalizar los
   generadores asíncronos*.

   Esta función no se puede llamar cuando otro bucle de eventos
   asyncio se está ejecutando en el mismo hilo.

   Si *debug* es "True", el bucle de eventos se ejecutará en modo
   debug.

   Esta función siempre crea un nuevo ciclo de eventos y lo cierra al
   final. Debe usarse como un punto de entrada principal para los
   programas asyncio, e idealmente solo debe llamarse una vez.

   Ejemplo:

      async def main():
          await asyncio.sleep(1)
          print('hello')

      asyncio.run(main())

   Nuevo en la versión 3.7.

   Nota:

     El código fuente para "asyncio.run()" se puede encontrar en
     Lib/asyncio/runners.py.


Creando Tareas
==============

asyncio.create_task(coro, *, name=None)

   Envuelve una coroutine *coro* en una "Task" y programa su
   ejecución. Retorna el objeto Tarea.

   Si *name* no es "None", se establece como el nombre de la tarea
   mediante "Task.set_name()".

   La tarea se ejecuta en el bucle retornado por "get_running_loop()",
   "RuntimeError" se genera si no hay ningún bucle en ejecución en el
   subproceso actual.

   Esta función se ha **añadido en Python 3.7**. Antes de Python 3.7,
   la función de bajo nivel "asyncio.ensure_future()" se puede
   utilizar en su lugar:

      async def coro():
          ...

      # In Python 3.7+
      task = asyncio.create_task(coro())
      ...

      # This works in all Python versions but is less readable
      task = asyncio.ensure_future(coro())
      ...

   Nuevo en la versión 3.7.

   Distinto en la versión 3.8: Se ha añadido el parámetro "name".


Durmiendo
=========

coroutine asyncio.sleep(delay, result=None, *, loop=None)

   Bloquea por *delay* segundos.

   Si se proporciona *result*, se retorna al autor de la llamada
   cuando se completa la corrutina.

   "sleep()" siempre suspende la tarea actual, permitiendo que se
   ejecuten otras tareas.

   Deprecated since version 3.8, will be removed in version 3.10: El
   parámetro *loop*.

   Ejemplo de una rutina que muestra la fecha actual cada segundo
   durante 5 segundos:

      import asyncio
      import datetime

      async def display_date():
          loop = asyncio.get_running_loop()
          end_time = loop.time() + 5.0
          while True:
              print(datetime.datetime.now())
              if (loop.time() + 1.0) >= end_time:
                  break
              await asyncio.sleep(1)

      asyncio.run(display_date())


Ejecutando Tareas Concurrentemente
==================================

awaitable asyncio.gather(*aws, loop=None, return_exceptions=False)

   Ejecute objetos esperables en la secuencia *aws* de forma
   *concurrently*.

   Si cualquier esperable en *aws* es una corrutina, se programa
   automáticamente como una Tarea.

   Si todos los esperables se completan correctamente, el resultado es
   una lista agregada de valores retornados. El orden de los valores
   de resultado corresponde al orden de esperables en *aws*.

   Si *return_exceptions* es "False" (valor predeterminado), la
   primera excepción provocada se propaga inmediatamente a la tarea
   que espera en "gather()". Otros esperables en la secuencia *aws*
   **no se cancelarán** y continuarán ejecutándose.

   Si *return_exceptions* es "True", las excepciones se tratan igual
   que los resultados correctos y se agregan en la lista de
   resultados.

   Si "gather()" es *cancelado*, todos los esperables enviados (que
   aún no se han completado) también se *cancelan*.

   Si alguna Tarea o Futuro de la secuencia *aws* se *cancela*, se
   trata como si se lanzara "CancelledError" -- la llamada "gather()"
   **no** se cancela en este caso. Esto es para evitar la cancelación
   de una Tarea/Futuro enviada para hacer que otras Tareas/Futuros
   sean canceladas.

   Deprecated since version 3.8, will be removed in version 3.10: El
   parámetro *loop*.

   Ejemplo:

      import asyncio

      async def factorial(name, number):
          f = 1
          for i in range(2, number + 1):
              print(f"Task {name}: Compute factorial({i})...")
              await asyncio.sleep(1)
              f *= i
          print(f"Task {name}: factorial({number}) = {f}")

      async def main():
          # Schedule three calls *concurrently*:
          await asyncio.gather(
              factorial("A", 2),
              factorial("B", 3),
              factorial("C", 4),
          )

      asyncio.run(main())

      # Expected output:
      #
      #     Task A: Compute factorial(2)...
      #     Task B: Compute factorial(2)...
      #     Task C: Compute factorial(2)...
      #     Task A: factorial(2) = 2
      #     Task B: Compute factorial(3)...
      #     Task C: Compute factorial(3)...
      #     Task B: factorial(3) = 6
      #     Task C: Compute factorial(4)...
      #     Task C: factorial(4) = 24

   Nota:

     If *return_exceptions* is False, cancelling gather() after it has
     been marked done won't cancel any submitted awaitables. For
     instance, gather can be marked done after propagating an
     exception to the caller, therefore, calling "gather.cancel()"
     after catching an exception (raised by one of the awaitables)
     from gather won't cancel any other awaitables.

   Distinto en la versión 3.7: Si se cancela el propio *gather*, la
   cancelación se propaga independientemente de *return_exceptions*.


Protección contra Cancelación
=============================

awaitable asyncio.shield(aw, *, loop=None)

   Protege un objeto esperable de ser "cancelado".

   Si *aw* es una corrutina, se programa automáticamente como una
   Tarea.

   La declaración:

      res = await shield(something())

   es equivalente a:

      res = await something()

   *excepto* que si la corrutina que lo contiene se cancela, la tarea
   que se ejecuta en "something()" no se cancela. Desde el punto de
   vista de "something()", la cancelación no ocurrió. Aunque su
   invocador siga cancelado, por lo que la expresión "await" sigue
   generando un "CancelledError".

   Si "something()" se cancela por otros medios (es decir, desde
   dentro de sí mismo) eso también cancelaría "shield()".

   Si se desea ignorar por completo la cancelación (no se recomienda)
   la función "shield()" debe combinarse con una cláusula try/except,
   como se indica a continuación:

      try:
          res = await shield(something())
      except CancelledError:
          res = None

   Deprecated since version 3.8, will be removed in version 3.10: El
   parámetro *loop*.


Tiempo agotado
==============

coroutine asyncio.wait_for(aw, timeout, *, loop=None)

   Espere a que el *aw* esperable se complete con un tiempo agotado.

   Si *aw* es una corrutina, se programa automáticamente como una
   Tarea.

   *timeout* puede ser "None" o punto flotante o un número entero de
   segundos a esperar. Si *timeout* es "None", se bloquea hasta que
   futuro se complete.

   Si se produce un agotamiento de tiempo, cancela la tarea y genera
   "asyncio.TimeoutError".

   Para evitar la "cancelación" de la tarea , envuélvala en
   "shield()".

   La función esperará hasta que el futuro este cancelado, por lo que
   el tiempo de espera total puede superar el *timeout*.

   Si se cancela la espera, el futuro *aw* también se cancela.

   Deprecated since version 3.8, will be removed in version 3.10: El
   parámetro *loop*.

   Ejemplo:

      async def eternity():
          # Sleep for one hour
          await asyncio.sleep(3600)
          print('yay!')

      async def main():
          # Wait for at most 1 second
          try:
              await asyncio.wait_for(eternity(), timeout=1.0)
          except asyncio.TimeoutError:
              print('timeout!')

      asyncio.run(main())

      # Expected output:
      #
      #     timeout!

   Distinto en la versión 3.7: Cuando *aw* se cancela debido a un
   agotamiento de tiempo, "wait_for" espera a que se cancele *aw*.
   Anteriormente, se lanzó inmediatamente "asyncio.TimeoutError".


Esperando Primitivas
====================

coroutine asyncio.wait(aws, *, loop=None, timeout=None, return_when=ALL_COMPLETED)

   Run awaitable objects in the *aws* iterable concurrently and block
   until the condition specified by *return_when*.

   Retorna dos conjuntos de Tareas/Futuros: "(done, pending)".

   Uso:

      done, pending = await asyncio.wait(aws)

   *timeout* (un punto flotante o int), si se especifica, se puede
   utilizar para controlar el número máximo de segundos que hay que
   esperar antes de retornar.

   Tenga en cuenta que esta función no lanza "asyncio.TimeoutError".
   Los Futuros o Tareas que no terminan cuando se agota el tiempo
   simplemente se retornan en el segundo conjunto.

   *return_when* indica cuándo debe retornar esta función. Debe ser
   una de las siguientes constantes:

   +-------------------------------+------------------------------------------+
   | Constante                     | Descripción                              |
   |===============================|==========================================|
   | "FIRST_COMPLETED"             | La función retornará cuando cualquier    |
   |                               | Futuro termine o se cancele.             |
   +-------------------------------+------------------------------------------+
   | "FIRST_EXCEPTION"             | La función retornará cuando cualquier    |
   |                               | Futuro finalice lanzando una excepción.  |
   |                               | Si ningún Futuro lanza una excepción,    |
   |                               | entonces es equivalente a                |
   |                               | "ALL_COMPLETED".                         |
   +-------------------------------+------------------------------------------+
   | "ALL_COMPLETED"               | La función retornará cuando todos los    |
   |                               | Futuros terminen o se cancelen.          |
   +-------------------------------+------------------------------------------+

   A diferencia de "wait_for()", "wait()" no cancela los Futuros
   cuando se produce un agotamiento de tiempo.

   Obsoleto desde la versión 3.8: Si cualquier aguardable en *aws* es
   una corrutina, se programa automáticamente como una Tarea. El paso
   de objetos corrutinas a "wait()" directamente está en desuso, ya
   que conduce a comportamiento confuso.

   Deprecated since version 3.8, will be removed in version 3.10: El
   parámetro *loop*.

   Nota:

     "wait()" programa las corrutinas como Tareas automáticamente y
     posteriormente retorna los objetos Tarea creados implícitamente
     en conjuntos "(done, pending)". Por lo tanto, el código siguiente
     no funcionará como se esperaba:

        async def foo():
            return 42

        coro = foo()
        done, pending = await asyncio.wait({coro})

        if coro in done:
            # This branch will never be run!

     Aquí es cómo se puede arreglar el fragmento de código anterior:

        async def foo():
            return 42

        task = asyncio.create_task(foo())
        done, pending = await asyncio.wait({task})

        if task in done:
            # Everything will work as expected now.

   Obsoleto desde la versión 3.8: El paso de objetos corrutina a
   "wait()" directamente está en desuso.

asyncio.as_completed(aws, *, loop=None, timeout=None)

   Run awaitable objects in the *aws* iterable concurrently.  Return
   an iterator of coroutines. Each coroutine returned can be awaited
   to get the earliest next result from the iterable of the remaining
   awaitables.

   Lanza "asyncio.TimeoutError" si el agotamiento de tiempo ocurre
   antes que todos los Futuros terminen.

   Deprecated since version 3.8, will be removed in version 3.10: El
   parámetro *loop*.

   Ejemplo:

      for coro in as_completed(aws):
          earliest_result = await coro
          # ...


Planificación Desde Otros Hilos
===============================

asyncio.run_coroutine_threadsafe(coro, loop)

   Envía una corrutina al bucle de eventos especificado. Seguro para
   Hilos.

   Retorna "concurrent.futures.Future" para esperar el resultado de
   otro hilo del SO (Sistema Operativo).

   Esta función está pensada para llamarse desde un hilo del SO
   diferente al que se ejecuta el bucle de eventos. Ejemplo:

      # Create a coroutine
      coro = asyncio.sleep(1, result=3)

      # Submit the coroutine to a given loop
      future = asyncio.run_coroutine_threadsafe(coro, loop)

      # Wait for the result with an optional timeout argument
      assert future.result(timeout) == 3

   Si se lanza una excepción en la corrutina, el Futuro retornado será
   notificado. También se puede utilizar para cancelar la tarea en el
   bucle de eventos:

      try:
          result = future.result(timeout)
      except asyncio.TimeoutError:
          print('The coroutine took too long, cancelling the task...')
          future.cancel()
      except Exception as exc:
          print(f'The coroutine raised an exception: {exc!r}')
      else:
          print(f'The coroutine returned: {result!r}')

   Consulte la sección de la documentación Concurrencia y multi hilos.

   A diferencia de otras funciones asyncio, esta función requiere que
   el argumento *loop* se pase explícitamente.

   Nuevo en la versión 3.5.1.


Introspección
=============

asyncio.current_task(loop=None)

   Retorna la instancia "Task" actualmente en ejecución o "None" si no
   se está ejecutando ninguna tarea.

   Si *loop* es "None" "get_running_loop()" se utiliza para obtener el
   bucle actual.

   Nuevo en la versión 3.7.

asyncio.all_tasks(loop=None)

   Retorna un conjunto de objetos "Task" que se ejecutan por el bucle.

   Si *loop* es "None", "get_running_loop()" se utiliza para obtener
   el bucle actual.

   Nuevo en la versión 3.7.


Objeto Task
===========

class asyncio.Task(coro, *, loop=None, name=None)

   Un objeto "similar a Futuro" que ejecuta Python coroutine. No es
   seguro hilos.

   Las tareas se utilizan para ejecutar corrutinas en bucles de
   eventos. Si una corrutina aguarda en un Futuro, la Tarea suspende
   la ejecución de la corrutina y espera la finalización del Futuro.
   Cuando el Futuro *termina*, se reanuda la ejecución de la corrutina
   envuelta.

   Los bucles de eventos usan la programación cooperativa: un bucle de
   eventos ejecuta una tarea a la vez. Mientras una Tarea espera para
   la finalización de un Futuro, el bucle de eventos ejecuta otras
   tareas, retorno de llamada o realiza operaciones de E/S.

   Utilice la función de alto nivel "asyncio.create_task()" para crear
   Tareas, o las funciones de bajo nivel "loop.create_task()" o
   "ensure_future()". Se desaconseja la creación de instancias
   manuales de Tareas.

   Para cancelar una Tarea en ejecución, utilice el método "cancel()".
   Llamarlo hará que la tarea lance una excepción "CancelledError" en
   la corrutina contenida. Si una corrutina está esperando en un
   objeto Futuro durante la cancelación, se cancelará el objeto
   Futuro.

   "cancelled()" se puede utilizar para comprobar si la Tarea fue
   cancelada. El método devuelve "True" si la corrutina contenida no
   suprimió la excepción "CancelledError" y se canceló realmente.

   "asyncio.Task" hereda de "Future" todas sus API excepto
   "Future.set_result()" y "Future.set_exception()".

   Las tareas admiten el módulo "contextvars". Cuando se crea una
   Tarea, copia el contexto actual y, posteriormente, ejecuta su
   corrutina en el contexto copiado.

   Distinto en la versión 3.7: Agregado soporte para el módulo
   "contextvars".

   Distinto en la versión 3.8: Se ha añadido el parámetro "name".

   Deprecated since version 3.8, will be removed in version 3.10: El
   parámetro *loop*.

   cancel()

      Solicita que se cancele la Tarea.

      Esto hace que una excepción "CancelledError" sea lanzada a la
      corrutina contenida en el próximo ciclo del bucle de eventos.

      La corrutina entonces tiene la oportunidad de limpiar o incluso
      denegar la solicitud suprimiendo la excepción con un bloque
      "try" ... ...``except CancelledError`` ... "finally". Por lo
      tanto, a diferencia de "Future.cancel()", "Task.cancel()" no
      garantiza que la tarea será cancelada, aunque suprimir la
      cancelación por completo no es común y se desalienta
      activamente.

      En el ejemplo siguiente se muestra cómo las corrutinas pueden
      interceptar la solicitud de cancelación:

         async def cancel_me():
             print('cancel_me(): before sleep')

             try:
                 # Wait for 1 hour
                 await asyncio.sleep(3600)
             except asyncio.CancelledError:
                 print('cancel_me(): cancel sleep')
                 raise
             finally:
                 print('cancel_me(): after sleep')

         async def main():
             # Create a "cancel_me" Task
             task = asyncio.create_task(cancel_me())

             # Wait for 1 second
             await asyncio.sleep(1)

             task.cancel()
             try:
                 await task
             except asyncio.CancelledError:
                 print("main(): cancel_me is cancelled now")

         asyncio.run(main())

         # Expected output:
         #
         #     cancel_me(): before sleep
         #     cancel_me(): cancel sleep
         #     cancel_me(): after sleep
         #     main(): cancel_me is cancelled now

   cancelled()

      Retorna "True" si la Tarea se *cancela*.

      La tarea se *cancela* cuando se solicitó la cancelación con
      "cancel()" y la corrutina contenida propagó la excepción
      "CancelledError" que se le ha lanzado.

   done()

      Retorna "True" si la Tarea está *finalizada*.

      Una tarea está *finalizada* cuando la corrutina contenida
      retornó un valor, lanzó una excepción, o se canceló la Tarea.

   result()

      Retorna el resultado de la Tarea.

      Si la tarea está *terminada*, se devuelve el resultado de la
      corrutina contenida (o si la corrutina lanzó una excepción, esa
      excepción se vuelve a relanzar.)

      Si la Tarea ha sido *cancelada*, este método lanza una excepción
      "CancelledError".

      Si el resultado de la Tarea aún no está disponible, este método
      lanza una excepción "InvalidStateError".

   exception()

      Retorna la excepción de la Tarea.

      Si la corrutina contenida lanzó una excepción, esa excepción es
      retornada. Si la corrutina contenida retorna normalmente, este
      método retorna "None".

      Si la Tarea ha sido *cancelada*, este método lanza una excepción
      "CancelledError".

      Si la Tarea aún no está *terminada*, este método lanza una
      excepción "InvalidStateError".

   add_done_callback(callback, *, context=None)

      Agrega una retro llamada que se ejecutará cuando la Tarea esté
      *terminada*.

      Este método solo se debe usar en código basado en retrollamada
      de bajo nivel.

      Consulte la documentación de "Future.add_done_callback()" para
      obtener más detalles.

   remove_done_callback(callback)

      Remueve la *retrollamada* de la lista de retrollamadas.

      Este método solo se debe usar en código basado en retrollamada
      de bajo nivel.

      Consulte la documentación de "Future.remove_done_callback()"
      para obtener más detalles.

   get_stack(*, limit=None)

      Retorna la lista de marcos de pila para esta tarea.

      Si la corrutina contenida no se termina, esto retorna la pila
      donde se suspende. Si la corrutina se ha completado
      correctamente o se ha cancelado, retorna una lista vacía. Si la
      corrutina terminó por una excepción, esto retorna la lista de
      marcos de seguimiento.

      Los marcos siempre se ordenan de más antiguo a más nuevo.

      Solo se retorna un marco de pila para una corrutina suspendida.

      El argumento opcional *limit* establece el número máximo de
      marcos que se retornarán; de forma predeterminada se retornan
      todos los marcos disponibles. El orden de la lista devuelta
      varía en función de si se retorna una pila o un *traceback*: se
      devuelven los marcos más recientes de una pila, pero se
      devuelven los marcos más antiguos de un *traceback*. (Esto
      coincide con el comportamiento del módulo traceback.)ss

   print_stack(*, limit=None, file=None)

      Imprime la pila o el seguimiento de esta tarea.

      Esto produce una salida similar a la del módulo traceback para
      los marcos recuperados por "get_stack()".

      El argumento *limit* se pasa directamente a "get_stack()".

      El argumento *file* es un flujo de E/S en el que se escribe la
      salida; por defecto, la salida se escribe en "sys.stderr".

   get_coro()

      Retorna el objeto corrutina contenido por "Task".

      Nuevo en la versión 3.8.

   get_name()

      Retorna el nombre de la Tarea.

      Si no se ha asignado explícitamente ningún nombre a la Tarea, la
      implementación de Tarea asyncio predeterminada genera un nombre
      predeterminado durante la creación de instancias.

      Nuevo en la versión 3.8.

   set_name(value)

      Establece el nombre de la Tarea.

      El argumento *value* puede ser cualquier objeto, que luego se
      convierte en una cadena.

      En la implementación de Task predeterminada, el nombre será
      visible en la salida "repr()" de un objeto de tarea.

      Nuevo en la versión 3.8.

   classmethod all_tasks(loop=None)

      Retorna un conjunto de todas las tareas para un bucle de
      eventos.

      De forma predeterminada, se retornan todas las tareas del bucle
      de eventos actual. Si *loop* es "None", la función
      "get_event_loop()" se utiliza para obtener el bucle actual.

      Deprecated since version 3.7, will be removed in version 3.9: No
      llame a esto como un método de tarea. Utilice la función
      "asyncio.all_tasks()" en su lugar.

   classmethod current_task(loop=None)

      Retorna la tarea que se está ejecutando actualmente o "None".

      Si *bucle* es "None", la función "get_event_loop()" se utiliza
      para obtener el bucle actual.

      Deprecated since version 3.7, will be removed in version 3.9: No
      llame a esto como un método de tarea. Utilice la función
      "asyncio.current_task()" en su lugar.


Corrutinas basadas en generadores
=================================

Nota:

  La compatibilidad con corrutinas basadas en generadores está **en
  desuso** y está programada para su eliminación en Python 3.10.

Las corrutinas basadas en generadores son anteriores a la sintaxis
async/await. Son generadores de Python que utilizan expresiones "yield
from" para esperar en Futuros y otras corrutinas.

Las corrutinas basadas en generadores deben estar decoradas con
"@asyncio.coroutine", aunque esto no se aplica.

@asyncio.coroutine

   Decorador para marcar corrutinas basadas en generadores.

   Este decorador permite que las corrutinas basadas en generadores de
   versiones anteriores (*legacy*) sean compatibles con el código
   async/await:

      @asyncio.coroutine
      def old_style_coroutine():
          yield from asyncio.sleep(1)

      async def main():
          await old_style_coroutine()

   Este decorador no debe utilizarse para corrutinas "async def".

   Deprecated since version 3.8, will be removed in version 3.10: Usar
   "async def" en su lugar.

asyncio.iscoroutine(obj)

   Retorna "True" si *obj* es un coroutine object.

   Este método es diferente de "inspect.iscoroutine()" porque retorna
   "True" para corrutinas basadas en generadores.

asyncio.iscoroutinefunction(func)

   Retorna "True" si *func* es una coroutine function.

   Este método es diferente de "inspect.iscoroutinefunction()" porque
   retorna "True" para funciones de corrutinas basadas en generadores
   decoradas con "@coroutine".
