Перед Python 3.5+ был отпущен, asyncio
модуль используется генераторы для имитации асинхронных вызовов и , таким образом , был другой синтаксис , чем текущая версия Python 3.5.
Модуль asyncio
Введение
Примеры
- 8
Синтаксис сопрограммы и делегирования
- 5
Асинхронные исполнители
Примечание. Использует асинхронный / ожидающий синтаксис Python 3.5+.
asyncio
поддерживает использованиеExecutor
объектов , найденные вconcurrent.futures
для планирования задач асинхронна. Петли событий имеют функциюrun_in_executor()
, который принимаетExecutor
объект,Callable
и параметры отзывных в.Планирование задачи для
Executor
import asyncio from concurrent.futures import ThreadPoolExecutor def func(a, b): # Do time intensive stuff... return a + b async def main(loop): executor = ThreadPoolExecutor() result = await loop.run_in_executor(executor, func, "Hello,", " world!") print(result) if __name__ == "__main__": loop = asyncio.get_event_loop() loop.run_until_complete(main(loop))
Каждый цикл событий также имеет « по умолчанию»
Executor
слот , который может быть назначен наExecutor
. Чтобы назначитьExecutor
и планировать задачи из цикла вы используетеset_default_executor()
метод.import asyncio from concurrent.futures import ThreadPoolExecutor def func(a, b): # Do time intensive stuff... return a + b async def main(loop): # NOTE: Using `None` as the first parameter designates the `default` Executor. result = await loop.run_in_executor(None, func, "Hello,", " world!") print(result) if __name__ == "__main__": loop = asyncio.get_event_loop() loop.set_default_executor(ThreadPoolExecutor()) loop.run_until_complete(main(loop))
Есть два основных типа
Executor
вconcurrent.futures
, темThreadPoolExecutor
иProcessPoolExecutor
.ThreadPoolExecutor
содержит пул потоков , которые могут быть либо вручную для определенного числа потоков через конструктор по умолчанию или к количеству ядер на время машины 5.ThreadPoolExecutor
использует пул потоков для выполнения задач , поставленных перед ней и обычно лучше при операциях с процессором, чем при операциях ввода-вывода. Контраст , что кProcessPoolExecutor
, который порождает новый процесс для каждой задачи , возложенной на него.ProcessPoolExecutor
может принимать только задачи и параметры, которые пригодны для консервирования. Наиболее распространенными задачами, которые нельзя отлавливать, являются методы объектов. Если вы должны запланировать метод объекта в качестве задачи вExecutor
необходимо использоватьThreadPoolExecutor
. - 3
Использование UVLoop
uvloop
является реализация дляasyncio.AbstractEventLoop
на основе libuv (используется nodejs). Это соответствует 99%asyncio
функций и гораздо быстрее , чем традиционноеasyncio.EventLoop
.uvloop
в настоящее время не доступно на Windows, установить его сpip install uvloop
.import asyncio import uvloop if __name__ == "__main__": asyncio.set_event_loop(uvloop.new_event_loop()) # Do your stuff here ...
Можно также изменить завод цикла событий, установив
EventLoopPolicy
на один вuvloop
.import asyncio import uvloop if __name__ == "__main__": asyncio.set_event_loop_policy(uvloop.EventLoopPolicy()) loop = asyncio.new_event_loop()
- 2
Примитив синхронизации: событие
концепция
Используйте
Event
для синхронизации планирования нескольких сопрограмм.Проще говоря, событие похоже на выстрел из пистолета в беговой гонке: оно позволяет бегунам покинуть стартовые блоки.
пример
import asyncio # event trigger function def trigger(event): print('EVENT SET') event.set() # wake up coroutines waiting # event consumers async def consumer_a(event): consumer_name = 'Consumer A' print('{} waiting'.format(consumer_name)) await event.wait() print('{} triggered'.format(consumer_name)) async def consumer_b(event): consumer_name = 'Consumer B' print('{} waiting'.format(consumer_name)) await event.wait() print('{} triggered'.format(consumer_name)) # event event = asyncio.Event() # wrap coroutines in one future main_future = asyncio.wait([consumer_a(event), consumer_b(event)]) # event loop event_loop = asyncio.get_event_loop() event_loop.call_later(0.1, functools.partial(trigger, event)) # trigger event in 0.1 sec # complete main_future done, pending = event_loop.run_until_complete(main_future)
Выход:
Потребитель Б ждет
Потребитель Ожидание
СОБЫТИЕ
Потребитель B сработал
Потребитель А сработал - 2
Простая паутина
Здесь мы делаем простое эхо WebSocket использования
asyncio
. Мы определяем сопрограммы для подключения к серверу и отправки / получения сообщений. В communcations по WebSocket выполняется вmain
сопрограммы, который выполняется с помощью цикла обработки событий. В этом примере изменяется от предыдущего поста .import asyncio import aiohttp session = aiohttp.ClientSession() # handles the context manager class EchoWebsocket: async def connect(self): self.websocket = await session.ws_connect("wss://echo.websocket.org") async def send(self, message): self.websocket.send_str(message) async def receive(self): result = (await self.websocket.receive()) return result.data async def main(): echo = EchoWebsocket() await echo.connect() await echo.send("Hello World!") print(await echo.receive()) # "Hello World!" if __name__ == '__main__': # The main loop loop = asyncio.get_event_loop() loop.run_until_complete(main())
- 2
Распространенное заблуждение об асинчо
вероятно, наиболее распространенное заблуждение о
asnycio
является то , что она позволяет запускать любую задачу параллельно - обходя GIL (глобальная блокировка интерпретатора) и , следовательно , выполнять блокирующие работу параллельно (в отдельных потоках). это не так!asyncio
(и библиотеки, которые строятся для совместной работы сasyncio
) строить сопрограмм: функции , которые (совместно) дают поток управления обратно в вызывающую функцию. обратите вниманиеasyncio.sleep
в приведенных выше примерах. это пример неблокируемой сопрограммы , что ждет «в фоновом режиме» и дает управляющий поток обратно в вызывающую функцию (при вызове сawait
).time.sleep
является примером функции блокировки. поток выполнения программы будет просто останавливаться и возвращать только после того, какtime.sleep
закончил.в режиме реального живой пример является
requests
библиотека , которая состоит (в настоящее время) на блокирование только функции. нет параллелизма , если вы звоните любой из ее функций вasyncio
.aiohttp
с другой стороны , был построен сasyncio
в виду. его сопрограммы будут работать одновременно.если вы затянувшийся CPU переплете задач , которые вы хотели бы работать параллельно
asyncio
не для вас. для этого вам нужноthreads
илиmultiprocessing
.-
если у вас есть IO-связанные задания работают, вы можете запустить их одновременно с помощью
asyncio
.