Асинхронната функционалност на Python за асинхронно програмиране или накратко async ви позволява да пишете програми, които да свършат повече работа, без да чакате независимите задачи да завършат. В asyncio
библиотеката са включени с Python ви дава инструментите за ползване асинхронен за обработка на диск или мрежа I / O, без да прави всичко останало изчакайте.
asyncio
предоставя два вида API за справяне с асинхронни операции: високо ниво и ниско ниво . Приложните програмни интерфейси (API) на високо ниво са най-общо полезни и са приложими за най-голямото разнообразие от приложения. Приложните програмни интерфейси (API) на ниско ниво са мощни, но и сложни и се използват по-рядко.
В тази статия ще се концентрираме върху API на високо ниво. В секциите по-долу ще разгледаме най-често използваните приложни програмни интерфейси (API) на високо ниво asyncio
и ще покажем как те могат да се използват за често срещани операции, включващи асинхронни задачи.
Ако сте напълно нови в асинхронизирането в Python или бихте могли да използвате опреснител за това как работи, прочетете моето въведение в Python async, преди да се потопите тук.
Стартирайте съпрограми и задачи в Python
Естествено, най-честата употреба за asyncio
е да се изпълняват асинхронните части на вашия Python скрипт. Това означава да се научите да работите с подпрограми и задачи.
Асинхронните компоненти на Python, включително съпрограми и задачи, могат да се използват само с други асинхронни компоненти, но не и с конвенционален синхронен Python, така че трябва asyncio
да преодолеете празнината. За да направите това, използвате asyncio.run
функцията:
внос asyncioasync def main ():
print ("Изчаква се 5 секунди.")
за _ в обхват (5):
очаквам asyncio.sleep (1)
print (".")
print ("Готово изчакване.")
asyncio.run (main ())
Това се изпълнява main()
, заедно с всички съпрограми main()
и се чака, за да се върне резултат.
Като общо правило програмата на Python трябва да има само един .run()
израз, както програмата на Python трябва да има само една main()
функция. Async, ако се използва небрежно, може да направи контролния поток на програма труден за четене. Наличието на една входна точка към асинхронния код на програмата предпазва нещата от косми.
Асинхронните функции също могат да бъдат насрочени като задачи или обекти, които обгръщат съпрограмите и помагат за тяхното изпълнение.
async def my_task ():направи нещо()
задача = asyncio.create_task (my_task ())
my_task()
след това се изпълнява в цикъла на събитията, като резултатите се съхраняват в task
.
Ако имате само една задача, от която искате да получите резултати, можете да използвате, за asyncio.wait_for(task)
да изчакате задачата да завърши, след което да използвате task.result()
за извличане на резултата. Но ако сте планирали изпълнение на няколко задачи и искате да изчакате всички да приключат, използвайте asyncio.wait([task1, task2])
за събиране на резултатите. (Имайте предвид, че можете да зададете време за изчакване на операциите, ако не искате те да се изпълняват след определен период от време.)
Управление на асинхронния цикъл на събития в Python
Друга често срещана употреба за asyncio
е управлението на асинхронния цикъл на събития . Цикълът на събитията е обект, който изпълнява асинхронни функции и обратно извикване; създава се автоматично, когато използвате asyncio.run()
. Обикновено искате да използвате само един цикъл на асинхронно събитие за програма, за да запазите нещата управляеми.
Ако пишете по-усъвършенстван софтуер, като сървър, ще ви е необходим достъп на по-ниско ниво до цикъла на събитията. За тази цел можете да „повдигнете капака“ и да работите директно с вътрешните елементи на цикъла на събитията. Но за прости работни места няма да е необходимо.
Четете и записвайте данни с потоци в Python
Най-добрият сценарий за асинхронизация са дълготрайни мрежови операции, при които приложението може да блокира чакането на някакъв друг ресурс да върне резултат. За тази цел asyncio
предлага потоци, които са механизми на високо ниво за извършване на мрежови I / O. Това включва дейността като сървър за мрежови заявки.
asyncio
използва два класа StreamReader
и StreamWriter
, за да чете и пише от мрежата на високо ниво. Ако искате да четете от мрежата, бихте използвали asyncio.open_connection()
за отваряне на връзката. Тази функция връща кортеж от StreamReader
и StreamWriter
обекти, както и можете да използвате .read()
и .write()
методи на всеки да общуват.
За да получавате връзки от отдалечени хостове, използвайте asyncio.start_server()
. Най- asyncio.start_server()
функцията се като аргумент и функция за обратна, client_connected_cb
, който се нарича, когато получи заявка. Тази функция за обратно извикване приема екземпляри StreamReader
и StreamWriter
като аргументи, така че можете да обработвате логиката за четене / запис на сървъра. (Вижте тук за пример за прост HTTP сървър, който използва библиотеката asyncio
-driven aiohttp
.)
Синхронизирайте задачите в Python
Асинхронните задачи обикновено се изпълняват изолирано, но понякога ще искате те да комуникират помежду си. asyncio
осигурява опашки и няколко други механизма за синхронизиране между задачите:
- Опашки :
asyncio
опашките позволяват на асинхронни функции да подреждат Python обекти, които да се консумират от други асинхронни функции - например за разпределяне на натоварванията между различни видове функции въз основа на тяхното поведение. - Примитиви на синхронизацията : Заключва, събития, условия и семафори в
asyncio
работата като техните конвенционални колеги на Python.
Едно нещо, което трябва да имате предвид за всички тези методи, е, че те не са безопасни за нишките. Това не е проблем за асинхронни задачи, изпълняващи се в същия цикъл на събития. Но ако се опитвате да споделяте информация със задачи в различен цикъл на събития, нишка на операционна система или процес, ще трябва да използвате threading
модула и неговите обекти, за да го направите.
Освен това, ако искате да стартирате съпрограми през границите на нишките, използвайте asyncio.run_coroutine_threadsafe()
функцията и предайте цикъла на събитията, за да използвате с нея като параметър.
Поставете на пауза съпрограма в Python
Друга често използвана asyncio
и недостатъчно обсъждана е изчакване на произволен период от време в съпрограмата. Не можете да използвате time.sleep()
за това, или ще блокирате цялата програма. Вместо това използвайте asyncio.sleep()
, което позволява на други съпрограми да продължат да се изпълняват.
Използвайте асинхронизиране на по-ниско ниво в Python
И накрая, ако смятате, че приложението, което изграждате, може да изисква asyncio
компоненти от по-ниско ниво, огледайте се, преди да започнете да кодирате: Има голяма вероятност някой вече да е изградил асинхронна Python библиотека, която прави това, от което се нуждаете.
Например, ако имате нужда от асинхронни DNS заявки, проверете aiodns
библиотеката и за асинхронни SSH сесии има asyncSSH
. Търсете в PyPI по ключовата дума „async“ (плюс други ключови думи, свързани със задачата) или проверете ръчно подготвения Awesome Asyncio списък за идеи.