Подлужный Олег 304 КФ GroupWork 10928
Вагапова Деши Насрудиновна, 316 группа GroupWork 11485
t1import asynciot1import asyncio
2from typing import Any, Callable, Dict, List, Optional2from typing import Any, Callable, Dict, List, Optional
33
4class Loop:4class Loop:
5    _jobs: List[Dict[str, Any]] = []5    _jobs: List[Dict[str, Any]] = []
6    _runner_task: Optional[asyncio.Task] = None6    _runner_task: Optional[asyncio.Task] = None
7    _lock: Optional[asyncio.Lock] = None7    _lock: Optional[asyncio.Lock] = None
88
9    def __call__(self, func: Callable[..., Any]):9    def __call__(self, func: Callable[..., Any]):
1010
11        async def wrapper(*args, **kwargs):11        async def wrapper(*args, **kwargs):
12            if Loop._lock is None:12            if Loop._lock is None:
13                Loop._lock = asyncio.Lock()13                Loop._lock = asyncio.Lock()
14            loop = asyncio.get_running_loop()14            loop = asyncio.get_running_loop()
15            fut = loop.create_future()15            fut = loop.create_future()
16            job = {'func': func, 'args': args, 'kwargs': kwargs, 'future16            job = {'func': func, 'args': args, 'kwargs': kwargs, 'future
>': fut, 'alive': True}>': fut, 'alive': True}
17            async with Loop._lock:17            async with Loop._lock:
18                Loop._jobs.append(job)18                Loop._jobs.append(job)
19                if Loop._runner_task is None:19                if Loop._runner_task is None:
20                    Loop._runner_task = asyncio.create_task(Loop._runner20                    Loop._runner_task = asyncio.create_task(Loop._runner
>())>())
21            await fut21            await fut
22            return None22            return None
23        return wrapper23        return wrapper
2424
25    @classmethod25    @classmethod
26    async def _runner(cls):26    async def _runner(cls):
27        if cls._lock is None:27        if cls._lock is None:
28            cls._lock = asyncio.Lock()28            cls._lock = asyncio.Lock()
29        dirty = False29        dirty = False
30        try:30        try:
31            while True:31            while True:
32                async with cls._lock:32                async with cls._lock:
33                    if not cls._jobs:33                    if not cls._jobs:
34                        cls._runner_task = None34                        cls._runner_task = None
35                        return35                        return
36                    snapshot = list(cls._jobs)36                    snapshot = list(cls._jobs)
37                for job in snapshot:37                for job in snapshot:
38                    if not job.get('alive', True):38                    if not job.get('alive', True):
39                        continue39                        continue
40                    try:40                    try:
41                        res = await job['func'](*job['args'], **job['kwa41                        res = await job['func'](*job['args'], **job['kwa
>rgs'])>rgs'])
42                    except Exception as exc:42                    except Exception as exc:
43                        job['alive'] = False43                        job['alive'] = False
44                        dirty = True44                        dirty = True
45                        if not job['future'].done():45                        if not job['future'].done():
46                            job['future'].set_exception(exc)46                            job['future'].set_exception(exc)
47                        continue47                        continue
48                    if res is None:48                    if res is None:
49                        for other in snapshot:49                        for other in snapshot:
50                            if other.get('alive', True):50                            if other.get('alive', True):
51                                other['alive'] = False51                                other['alive'] = False
52                                if not other['future'].done():52                                if not other['future'].done():
53                                    other['future'].set_result(None)53                                    other['future'].set_result(None)
54                        dirty = True54                        dirty = True
55                        break55                        break
56                if dirty:56                if dirty:
57                    async with cls._lock:57                    async with cls._lock:
58                        cls._jobs = [j for j in cls._jobs if j.get('aliv58                        cls._jobs = [j for j in cls._jobs if j.get('aliv
>e', True)]>e', True)]
59                        if not cls._jobs:59                        if not cls._jobs:
60                            cls._runner_task = None60                            cls._runner_task = None
61                            return61                            return
62                    dirty = False62                    dirty = False
63                async with cls._lock:63                async with cls._lock:
64                    if not cls._jobs:64                    if not cls._jobs:
65                        cls._runner_task = None65                        cls._runner_task = None
66                        return66                        return
67        finally:67        finally:
68            async with cls._lock:68            async with cls._lock:
69                for job in cls._jobs:69                for job in cls._jobs:
70                    if not job['future'].done():70                    if not job['future'].done():
71                        job['future'].set_result(None)71                        job['future'].set_result(None)
72                cls._jobs.clear()72                cls._jobs.clear()
73                cls._runner_task = None73                cls._runner_task = None
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op