import asyncio
import time
async def func():
print('task start')
await asyncio.sleep(10)
print('task end')
async def main():
task1 = asyncio.create_task(func())
task2 = asyncio.create_task(func())
task3 = asyncio.create_task(func())
task4 = asyncio.create_task(func())
s = time.monotonic()
print('main start', time.monotonic() - s)
await task1
print('main continue', time.monotonic() - s)
await task2
print('main continue', time.monotonic() - s)
await task3
print('main continue', time.monotonic() - s)
await task4
print('main end', time.monotonic() - s)
asyncio.run(main())
Ten kod daje wyniki jak poniżej:
main start 0.0
task start
task start
task start
task start
task end
task end
task end
task end
main continue 10.0
main continue 10.0
main continue 10.0
main end
Ale jak to możliwe, Python ominął moje poprzednie wywołania print, najpierw uruchomił awaitables, a następnie wrócił do wywołań print, jak mam to zrozumieć?
2 odpowiedzi
Wszystkie Twoje zadania śpią przez 10 sekund, a następnie kontynuuj i zakończ niemal natychmiast. Zatem wszystkie wywołania await
zostaną odblokowane w tym samym czasie, ponieważ po zakończeniu zadania 1 wszystkie zadania również zostaną zakończone.
Masz rację w tym sensie, że technicznie mogłeś przeplatać wydruki między task end
a main continue
, ale myślę, że jest to szczegół implementacji, który wydaje się być zgrupowany.
Myślę, że możesz lepiej zrozumieć, co się dzieje, korzystając z tego zmodyfikowanego skryptu:
import asyncio
import time
async def func(task_nb, wait):
print('[%s] task start' % task_nb)
await asyncio.sleep(wait)
print('[%s] task end' % task_nb)
async def main():
task1 = asyncio.create_task(func(1, 1))
task2 = asyncio.create_task(func(2, 5))
task3 = asyncio.create_task(func(3, 7))
task4 = asyncio.create_task(func(4, 2))
s = time.monotonic()
print('main start', time.monotonic() - s)
await task1
print('main continue', time.monotonic() - s)
await task2
print('main continue', time.monotonic() - s)
await task3
print('main continue', time.monotonic() - s)
await task4
print('main end', time.monotonic() - s)
asyncio.run(main())
Będziesz mieć bardziej interesujące zachowanie await
:
main start 1.81000359589234e-07
[1] task start
[2] task start
[3] task start
[4] task start
[1] task end
main continue 1.0019499360005284
[4] task end
[2] task end
main continue 5.001785704000213
[3] task end
main continue 7.003587035000237
main end 7.003632674000073
Twój kod robi to, co powinien, zgodnie ze specyfikacją asyncio
, ale być może nie rozumiesz, czym jest „zadanie”.
Z dokumentów:
asyncio.create_task(coro, *, name=None)
Owiń coro coroutine w zadanie i zaplanuj jego wykonanie. Zwróć obiekt Task.
Oznacza to, że ponieważ utworzyłeś 4 zadania na początku swojego głównego zadania, wszystkie są zaplanowane do wykonania w tym samym czasie. I tak wszystkie drukują task start
razem, a potem task end
razem, w którym to momencie wszystkie Twoje await
natychmiast wypadają, ponieważ wszystkie zadania są zakończone w tym samym czasie (10 sekund później ). W końcu widzisz main continue 10.0
3 razy.
Wypróbuj ten kod, uważam, że będzie on zachowywał się tak, jak tego oczekujesz.
async def main():
task1 = func()
task2 = func()
task3 = func()
task4 = func()
...
Podobne pytania
Nowe pytania
python
Python to wielozadaniowy, wielozadaniowy język programowania dynamicznie typowany. Został zaprojektowany tak, aby był szybki do nauczenia się, zrozumienia i użycia oraz wymuszania czystej i jednolitej składni. Należy pamiętać, że Python 2 oficjalnie nie jest obsługiwany od 01-01-2020. Mimo to, w przypadku pytań Pythona specyficznych dla wersji, dodaj znacznik [python-2.7] lub [python-3.x]. Korzystając z wariantu Pythona (np. Jython, PyPy) lub biblioteki (np. Pandas i NumPy), należy umieścić go w tagach.