Advertisement
BERKYT

Untitled

Oct 22nd, 2024
68
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 9.12 KB | None | 0 0
  1. """
  2. Основные определения
  3. """
  4. import asyncio
  5. import types
  6.  
  7.  
  8. # платформенная сопрограмма
  9. async def coro():
  10.     await asyncio.sleep(1)
  11.  
  12.  
  13. def gen():
  14.     yield 11
  15.  
  16.  
  17. # Классическая сопрограмма
  18. def classic_coro():
  19.     for _ in range(10):
  20.         yield from gen()
  21.         x = yield "YIELD"
  22.         print(x)
  23.  
  24.  
  25. c = classic_coro()
  26.  
  27. print(next(c))
  28. print(next(c))
  29. c.send(1)
  30. print(next(c))
  31. c.send(2)
  32. print(next(c))
  33. c.send(3)
  34.  
  35.  
  36. # Генераторные сопрограммы
  37. @types.coroutine
  38. def gen_coro():
  39.     for _ in range(10):
  40.         yield from asyncio.sleep(1)
  41.  
  42.  
  43. async def test():
  44.     await gen_coro()
  45.  
  46.  
  47. # asyncio.run(test())
  48.  
  49. """
  50. В asyncio есть генератор, отдающий переданные ему сопрограммы, в порядке готовности, а не в порядке подачи.
  51.  
  52. Это выглядит как параллельное исполнение сопрограмм
  53. """
  54.  
  55. import random
  56.  
  57.  
  58. async def test_coro(id_: int):
  59.     await asyncio.sleep(random.randint(1, 5))
  60.     return id_
  61.  
  62.  
  63. async def task(id_: int):
  64.     await asyncio.sleep(5)
  65.     return id_
  66.  
  67.  
  68. async def main_test():
  69.     coros = []
  70.     tasks = []
  71.  
  72.     for i in range(5):
  73.         tasks.append(
  74.             asyncio.create_task(task(i))
  75.         )
  76.  
  77.     for i in range(5):
  78.         coros.append(test_coro(i))
  79.  
  80.     for c in asyncio.as_completed(coros):
  81.         print("ID: ", await c)
  82.  
  83.     # Таски выполняются в фоне, хоть и спят. 5 сек. Они спят асинхронно с test_coro корутинами.
  84.     # Нам необязательно дожидаться, пока таска будет выполнена. Но если вы этого хотим, достаточно просто
  85.     # вызвать таску с await если мы хотим передать ей управление в конкретной корутине
  86.     for t in asyncio.as_completed(tasks):
  87.         print("TASK ID: ", await t)
  88.  
  89.  
  90. # asyncio.run(main_test())
  91.  
  92. """
  93. Если вы не можете переписать блокирующую функцию, как асинхронную. То её надо запустить в отдельном потоке или процессе.
  94. """
  95.  
  96. """
  97. В asyncio есть возможность использовать семафоры и потоки.
  98.  
  99. Семафор работает так: асинхронный контекстный менеджер семафора в asyncio не блокирует программу целиком.
  100. Он блокирует только конкретную сопрограмму, если счетчик семаформа обращается в ноль.
  101.  
  102. Также, можно вынести отдельную функцию в поток, если нет возможности сделать её асинхронной.
  103. """
  104.  
  105. import time
  106.  
  107.  
  108. def dont_coro(id_: int):
  109.     time.sleep(2)
  110.  
  111.     return id_
  112.  
  113.  
  114. # Выполнение в отдельном потоке и асинхронно
  115. async def test_thread():
  116.     thread_tasks = []
  117.  
  118.     for i in range(5):
  119.         thread_tasks.append(asyncio.create_task(asyncio.to_thread(dont_coro, i)))
  120.  
  121.     print("test")
  122.  
  123.     for _, dc in zip(range(10), asyncio.as_completed(thread_tasks)):
  124.         print("T ID: ", await dc)
  125.         await asyncio.sleep(1)
  126.         print("HELLO FROM test_thread")
  127.  
  128.  
  129. # asyncio.run(test_thread())
  130.  
  131. """
  132. Рекомендуется помещать перед ASGI приложением прокси-сервер, который обрабатывает все статические файлы, а также по
  133. возможности, использовать CDN(система доставки контента)
  134.  
  135. В состав FastAPI входят скрипты для генерации проектов
  136. """
  137.  
  138.  
  139. async def value():
  140.     return random.randint(1, 10)
  141.  
  142.  
  143. # Асинхронные генераторы
  144. async def agen():
  145.     for _ in range(5):
  146.         yield await value()
  147.  
  148.  
  149. async def main():
  150.     async for v in agen():
  151.         print(v)
  152.  
  153.  
  154. # asyncio.run(main())
  155.  
  156. """
  157. Чтобы сделать так, чтобы Асинхронные генераторы стали поддерживать контекстные менеджеры, надо применить к ним
  158. декоратор asynccontextmanager
  159. """
  160.  
  161.  
  162. # Пример асинхронного включения:
  163. async def acomp():
  164.     print([x async for x in agen()])
  165.  
  166.  
  167. # asyncio.run(acomp())
  168.  
  169.  
  170. """
  171. Также можно определить асинхронное генераторное выражение (x async for x in agen()) где угодно в программе,
  172. но использовать его можно только в контексте асинхронного кода.
  173. """
  174.  
  175. """
  176. Чтобы контролировать исключения в функции
  177.  
  178. asyncio.gather()
  179.  
  180. Надо задать аргумент return_exceptions при вызове как return_exceptions=True
  181.  
  182. По умолчанию return_exceptions=False
  183. """
  184.  
  185. """
  186. Если вручную создать таски в через create_task, то надо дождаться, что они закончатся явно.
  187.  
  188. Например через await или as_complited
  189.  
  190. """
  191.  
  192. """
  193. У каждой задачи можно задать имя, это можно использовать как id задачи)))))))))))))))))
  194.  
  195. Пример:
  196.  
  197. """
  198.  
  199.  
  200. async def some_task(wait: int) -> int:
  201.     print("some_task with wait: ", wait)
  202.     await asyncio.sleep(wait)
  203.  
  204.     return 42
  205.  
  206.  
  207. async def some_main():
  208.     tasks = [
  209.         asyncio.create_task(some_task(num), name=f"number_{num}") for num in range(5)
  210.     ]
  211.  
  212.     for task in tasks:
  213.         print("...")
  214.         await task
  215.  
  216.         if task.get_name() == "number_4":
  217.             print("NUM 4 IS RUNNING!")
  218.  
  219.             task.cancel()
  220.             print("NUM 4 IS CANCELED!")
  221.  
  222.  
  223. # asyncio.run(some_main())
  224.  
  225.  
  226. """
  227. Задачи можно отменить с помощью метода .cancel() с обычными корутинами так не сделать.
  228. """
  229.  
  230. """
  231. Документация по Python 3.11+ рекомендует использовать TaskGroup() вместо gather()
  232.  
  233. TaskGroup - это асинхронный контекстный менеджер. Все таски в нем создаются, но await'тя после уже выхода из контекста
  234.  
  235. Пример:
  236. """
  237.  
  238.  
  239. async def task(id_: int):
  240.     await asyncio.sleep(1)
  241.     print(f"Hello from task with id: {id_}")
  242.  
  243.     if id_ % 2 == 0:
  244.         raise Exception
  245.  
  246.     return id_ * 100
  247.  
  248.  
  249. # Можно выполнить хоть 500 задач, все равно они будут выполнены за ~1 секунду
  250. async def task_group():
  251.     results = []
  252.  
  253.     try:
  254.         async with asyncio.TaskGroup() as tasks:
  255.             for i in range(500):
  256.                 results.append(
  257.                     tasks.create_task(
  258.                         task(i)
  259.                     )
  260.                 )
  261.  
  262.             print("inner context manager")
  263.     except Exception as e:
  264.         print(f"ERROR: {e}")
  265.  
  266.     """
  267.        ПО КАКОЙ-ТО ПРИЧИНЕ, ИСКЛЮЧЕНИЕ ПРОБРАСЫВАЕТСЯ НЕ ТОЛЬКО В КОНТЕКСТНЫЙ МЕНЕДЖЕР, НО И В МЕТОД
  268.  
  269.        .result()
  270.    """
  271.  
  272.     try:
  273.         # Получение результатов от задач
  274.         print("outer context manager", [t.result() for t in results])
  275.     except:
  276.         ...
  277.  
  278.  
  279. # asyncio.run(task_group())
  280.  
  281.  
  282. """
  283. Есть также возможость запустить задачи через wait.
  284.  
  285. Интересный способ. По завершению wait вернет список выполненых задач и тех, которые были не выполнены.
  286. Например, из-за таймаута
  287.  
  288. wait имеет параметр return_when у которого есть 3 состояния:
  289.  
  290.    * FIRST_COMPLETED - Вернуть done, pending когда выполнена, хотя бы одна задача
  291.    * FIRST_EXCEPTION - вернуть done, pending когда было хотя бы одно исключение
  292.    * ALL_COMPLETED(По умолчанию) - done, pending, когда выполнены все задачи
  293.  
  294. Пример:
  295. """
  296.  
  297.  
  298. async def wait_task(wait_time: int):
  299.     await asyncio.sleep(wait_time)
  300.  
  301.  
  302. async def wait_test():
  303.     tasks = [
  304.         asyncio.create_task(wait_task(1), name="d1"),
  305.         asyncio.create_task(wait_task(2), name="d2"),
  306.         asyncio.create_task(wait_task(3), name="d3"),
  307.     ]
  308.  
  309.     done, pending = await asyncio.wait(tasks, timeout=2.1)
  310.  
  311.     print(
  312.         f"{[d.get_name() for d in done]}, "
  313.         f"{[p.get_name() for p in pending]}"
  314.     )
  315.  
  316.  
  317. # asyncio.run(wait_test())
  318.  
  319.  
  320. """
  321. Для работы с файлами асинхронно можно юзать aiofiles это внешная библиотека
  322. """
  323.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement