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