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-268709555ensure_future
adiciona automaticamente o criadoTask
ao ciclo de eventos principal?loop
argumento de palavra-chave ( consulte a assinatura garantir_future ).await
dentromsg()
para retornar o controle ao loop de eventos na segunda chamada. O loop de eventos, uma vez que receba o controle, poderá ser iniciadolong_operation()
. Foi feito para demonstrar como aensure_future
co-rotina começa a ser executada simultaneamente com o fluxo de execução atual.create_task()
ensure_future()
create_task
,Como você pode ver, o create_task é mais específico.
async
função sem criar_task ou garantir_futureasync
Função de invocação simples retorna co-rotinaE uma vez que os
gather
bastidores garantem (ensure_future
) que args são futuros, explicitamenteensure_future
é redundante.Pergunta semelhante Qual é a diferença entre loop.create_task, asyncio.async / verify_future e Task?
fonte
Dos documentos oficiais:
Detalhe:
Portanto, agora, no Python 3.7 em diante, existem 2 funções de wrapper de nível superior (semelhantes, mas diferentes):
asyncio.create_task
: que simplesmente chamaevent_loop.create_task(coro)
diretamente. ( veja o código fonte )ensure_future
que também chamaevent_loop.create_task(coro)
se for co-rotina ou simplesmente para garantir que o tipo de retorno seja um asyncio.Future . ( veja o código-fonte ). De qualquer forma,Task
ainda éFuture
devido à sua herança de classe ( ref ).Bem, ao final, ambas as funções do wrapper irão ajudá-lo a chamar
BaseEventLoop.create_task
. A única diferença éensure_future
aceitar qualquerawaitable
objeto e ajudá-lo a convertê-lo em um Futuro. E você também pode fornecer seu próprioevent_loop
parâmetro emensure_future
. E dependendo se você precisa desses recursos ou não, você pode simplesmente escolher qual wrapper usar.fonte
para seu exemplo, todos os três tipos são executados de forma assíncrona. a única diferença é que, no terceiro exemplo, você pré-gerou todas as 10 corrotinas e as submeteu ao loop juntas. portanto, apenas o último fornece saída aleatoriamente.
fonte