Czasami trzeba wykonać jakąś niekrytyczną operację asynchroniczną, ale nie chcę czekać na jej zakończenie. W standardowej implementacji Tornado można „odpalić i zapomnieć” funkcję asynchroniczną, po prostu pomijając yield
słowo kluczowe.
Próbowałem wymyślić, jak „odpalić i zapomnieć” z nową składnią async
/ await
wydaną w Pythonie 3.5. Np. Uproszczony fragment kodu:
async def async_foo():
print("Do some stuff asynchronously here...")
def bar():
async_foo() # fire and forget "async_foo()"
bar()
Jednak dzieje się tak, że bar()
nigdy się nie uruchamia, a zamiast tego otrzymujemy ostrzeżenie w czasie wykonywania:
RuntimeWarning: coroutine 'async_foo' was never awaited
async_foo() # fire and forget "async_foo()"
python
python-3.5
python-asyncio
Mike N
źródło
źródło
Odpowiedzi:
Aktualizacja:
Wymień
asyncio.ensure_future
sięasyncio.create_task
wszędzie, jeśli używasz Python> = 3.7 jest nowszy, ładniejszy sposób do odradzania zadania .asyncio.Zrób „odpal i zapomnij”
Zgodnie z dokumentacją Pythona
asyncio.Task
, możliwe jest uruchomienie programu do wykonywania "w tle" . Zadanie utworzone przezasyncio.ensure_future
funkcję nie zablokuje wykonania (dlatego funkcja wróci natychmiast!). Wygląda to na sposób na „odpalenie i zapomnienie”, jak prosiłeś.Wynik:
Co się stanie, jeśli zadania są wykonywane po zakończeniu pętli zdarzeń?
Zauważ, że asyncio oczekuje, że zadanie zostanie zakończone w momencie zakończenia pętli zdarzeń. Więc jeśli zmienisz
main()
na:Po zakończeniu programu otrzymasz to ostrzeżenie:
Aby temu zapobiec, możesz po prostu poczekać na wszystkie oczekujące zadania po zakończeniu pętli zdarzeń:
Zabijaj zadania zamiast czekać na nie
Czasami nie chcesz czekać na wykonanie zadań (na przykład niektóre zadania mogą być tworzone tak, aby działały wiecznie). W takim przypadku możesz je po prostu anulować () zamiast czekać:
Wynik:
źródło
stop()
metodzie.Dziękuję Siergiej za zwięzłą odpowiedź. Oto zdobiona wersja tego samego.
Produkuje
Uwaga: sprawdź moją drugą odpowiedź, która robi to samo, używając zwykłych wątków.
źródło
To nie jest całkowicie asynchroniczne wykonanie, ale może run_in_executor () jest dla Ciebie odpowiednie.
źródło
executor
wola domyślnie dzwoniconcurrent.futures.ThreadPoolExecutor.submit()
. Wspominam, ponieważ tworzenie wątków nie jest darmowe; fire-and-zapominając 1000 razy na sekundę prawdopodobnie spowoduje duże obciążenie dla gospodarki gwintuZ jakiegoś powodu, jeśli nie możesz użyć,
asyncio
oto implementacja wykorzystująca zwykłe wątki. Sprawdź moje inne odpowiedzi i odpowiedź Siergieja.źródło