| f | import asyncio | f | import asyncio |
| from collections import deque | | from collections import deque |
| | | |
| class Loop: | | class Loop: |
| n | """Параметрический декоратор для корутин с синхронизацией выполнения | n | |
| """ | | |
| _coros = [] | | |
| _args_kwargs = [] | | _tasks = [] |
| | | _params = [] |
| _current = 0 | | _cursor = 0 |
| _done = False | | |
| _scheduled = False | | _finished = False |
| | | _active = False |
| | | |
| def __init__(self): | | def __init__(self): |
| n | self.index = len(Loop._coros) | n | self._id = len(Loop._tasks) |
| | | Loop._tasks.append(None) |
| Loop._coros.append(None) | | Loop._params.append(None) |
| Loop._args_kwargs.append(None) | | |
| | | |
| n | def __call__(self, coro): | n | def __call__(self, fn): |
| Loop._coros[self.index] = coro | | Loop._tasks[self._id] = fn |
| | | |
| n | async def wrapper(*args, **kwargs): | n | async def launcher(*args, **kwargs): |
| Loop._args_kwargs[self.index] = (args, kwargs) | | Loop._params[self._id] = (args, kwargs) |
| if not Loop._scheduled: | | if not Loop._active: |
| Loop._scheduled = True | | Loop._active = True |
| return await Loop._run_scheduler() | | return await Loop._run_scheduler() |
| return None | | return None |
| n | return wrapper | n | return launcher |
| | | |
| @classmethod | | @classmethod |
| async def _run_scheduler(cls): | | async def _run_scheduler(cls): |
| n | """Планировщик, который выполняет все корутины по очереди""" | n | |
| step = 0 | | pointer = 0 |
| total_coros = len(cls._coros) | | count = len(cls._tasks) |
| while not cls._done: | | while not cls._finished: |
| idx = step % total_coros | | slot = pointer % count |
| coro = cls._coros[idx] | | task = cls._tasks[slot] |
| args_kwargs = cls._args_kwargs[idx] | | payload = cls._params[slot] |
| if coro is None or args_kwargs is None: | | if task is None or payload is None: |
| step += 1 | | pointer += 1 |
| await asyncio.sleep(0) | | await asyncio.sleep(0) |
| continue | | continue |
| n | args, kwargs = args_kwargs | n | args, kwargs = payload |
| try: | | try: |
| n | result = await coro(*args, **kwargs) | n | outcome = await task(*args, **kwargs) |
| except asyncio.CancelledError: | | except asyncio.CancelledError: |
| n | cls._done = True | n | cls._finished = True |
| return None | | return None |
| n | if result is None: | n | if outcome is None: |
| cls._done = True | | cls._finished = True |
| return None | | return None |
| t | step += 1 | t | pointer += 1 |
| await asyncio.sleep(0) | | await asyncio.sleep(0) |
| return None | | return None |