Informação real:
A partir do Python 3.7 asyncio.create_task(coro)
, a função de alto nível foi adicionada para esse propósito.
Você deve usá-lo em vez de outras maneiras de criar tarefas de co-rotinas. No entanto, se você precisar criar uma tarefa arbitrária, deve usar asyncio.ensure_future(obj)
.
Informação antiga:
ensure_future
vs create_task
ensure_future
é um método para criar Task
a partir de coroutine
. Ele cria tarefas de maneiras diferentes com base em argumentos (incluindo o uso decreate_task
para co-rotinas e objetos semelhantes ao futuro).
create_task
é um método abstrato de AbstractEventLoop
. Loops de eventos diferentes podem implementar essa função de maneiras diferentes.
Você deve usar ensure_future
para criar tarefas. Você precisarácreate_task
apenas se for implementar seu próprio tipo de loop de evento.
Upd:
@ bj0 apontou para a resposta de Guido sobre este assunto:
O ponto de ensure_future()
é se você tem algo que poderia ser uma co-rotina ou um Future
(o último inclui um Task
porque é uma subclasse de Future
), e você deseja ser capaz de chamar um método nele que está definido apenas em Future
(provavelmente sobre o único exemplo útil sendo cancel()
). Quando já é um Future
(ou Task
), isso não faz nada; quando é uma co-rotina, envolve -a em a Task
.
Se você sabe que tem uma co-rotina e deseja que ela seja agendada, a API correta a ser usada é create_task()
. O único momento em que você deve chamar ensure_future()
é quando está fornecendo uma API (como a maioria das próprias APIs do asyncio) que aceita uma co-rotina ou a Future
e você precisa fazer algo que exija que você tenha uma Future
.
e depois:
No final, eu ainda acredito que ensure_future()
é um nome apropriadamente obscuro para uma funcionalidade raramente necessária. Ao criar uma tarefa a partir de uma co-rotina, você deve usar o nome apropriado
loop.create_task()
. Talvez devesse haver um apelido para isso
asyncio.create_task()
?
É surpreendente para mim. Minha principal motivação para usar o tempo ensure_future
todo foi que é uma função de nível superior em comparação com o membro do loopcreate_task
(a discussão contém algumas idéias como adicionar asyncio.spawn
ouasyncio.create_task
).
Também posso apontar que, na minha opinião, é muito conveniente usar uma função universal que pode lidar com qualquer Awaitable
vez de apenas co-rotinas.
No entanto, a resposta de Guido é clara: "Ao criar uma tarefa a partir de uma co-rotina, você deve usar o nome apropriadoloop.create_task()
"
Quando as corrotinas devem ser envolvidas nas tarefas?
Envolva a co-rotina em uma Tarefa - é uma maneira de iniciar esta co-rotina "em segundo plano". Aqui está um exemplo:
import asyncio
async def msg(text):
await asyncio.sleep(0.1)
print(text)
async def long_operation():
print('long_operation started')
await asyncio.sleep(3)
print('long_operation finished')
async def main():
await msg('first')
# Now you want to start long_operation, but you don't want to wait it finised:
# long_operation should be started, but second msg should be printed immediately.
# Create task to do so:
task = asyncio.ensure_future(long_operation())
await msg('second')
# Now, when you want, you can await task finised:
await task
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
Resultado:
first
long_operation started
second
long_operation finished
Você pode substituir asyncio.ensure_future(long_operation())
apenas await long_operation()
para sentir a diferença.
create_task
se realmente precisar de um objeto de tarefa, que normalmente não deveria: github.com/python/asyncio/issues/477#issuecomment-268709555