Сагура Николай, 392, сев. филиал TwoWay 10440
Лукьянов Артём Васильевич, 317, Севастопольский филилал TwoWay 11042
f1import asynciof1import asyncio
22
3class Portal:3class Portal:
44
5    def __init__(self, parties: int):5    def __init__(self, parties: int):
n6        self._parties = partiesn6        self._total = parties
7        self._generation = 07        self._phase = 0
8        self._n_waiting = 08        self._count = 0
9        self._event = asyncio.Event()9        self._phase_event = asyncio.Event()
10        self._broken = False10        self._is_broken = False
11        self._lock = asyncio.Lock()11        self._mutex = asyncio.Lock()
12        self._topic = None12        self._last_topic = None
13        self._pending_topic = {}13        self._phase_topics_pending = {}
14        self._gen_topic = {}14        self._phase_topics = {}
15        self._task_gen = {}15        self._task_phase = {}
16        self._task_index = {}16        self._task_slot = {}
1717
18    @property18    @property
n19    def parties(self) -> int:n19    def parties(self):
20        return self._parties20        return self._total
2121
22    @property22    @property
n23    def n_waiting(self) -> int:n23    def n_waiting(self):
24        return self._n_waiting24        return self._count
2525
26    @property26    @property
n27    def broken(self) -> bool:n27    def broken(self):
28        return self._broken28        return self._is_broken
2929
30    @property30    @property
31    def topic(self):31    def topic(self):
32        """32        """
n33        Для задач возвращаем топик их собственного прохода,n33        Для текущей задачи → её топик фазы.
34        для внешнего кода — последний глобальный топик.34        Для внешнего кода  глобальный последний топик.
35        """35        """
36        task = asyncio.current_task()36        task = asyncio.current_task()
37        if task is not None:37        if task is not None:
n38            gen = self._task_gen.get(task)n38            ph = self._task_phase.get(task)
39            if gen is not None:39            if ph is not None:
40                topic = self._gen_topic.get(gen, None)40                t = self._phase_topics.get(ph)
41                if topic is not None:41                if t is not None:
42                    return topic42                    return t
43        return self._topic43        return self._last_topic
4444
45    async def wait(self, topic=None):45    async def wait(self, topic=None):
n46        if self._broken:n46        if self._is_broken:
47            raise asyncio.BrokenBarrierError47            raise asyncio.BrokenBarrierError
48        task = asyncio.current_task()48        task = asyncio.current_task()
n49        async with self._lock:n49        async with self._mutex:
50            gen = self._generation50            phase = self._phase
51            self._task_gen[task] = gen51            self._task_phase[task] = phase
52            if topic is not None:52            if topic is not None:
n53                self._pending_topic[gen] = topicn53                self._phase_topics_pending[phase] = topic
54            self._n_waiting += 154            self._count += 1
55            index = self._parties - self._n_waiting55            slot = self._total - self._count
56            self._task_index[task] = index56            self._task_slot[task] = slot
57            my_event = self._event57            my_event = self._phase_event
58            if self._n_waiting == self._parties:58            if self._count == self._total:
59                gen_topic = self._pending_topic.pop(gen, None)59                phase_topic = self._phase_topics_pending.pop(phase, None
 >)
60                self._gen_topic[gen] = gen_topic60                self._phase_topics[phase] = phase_topic
61                self._topic = gen_topic61                self._last_topic = phase_topic
62                self._generation += 162                self._phase += 1
63                self._n_waiting = 063                self._count = 0
64                self._event = asyncio.Event()64                self._phase_event = asyncio.Event()
65                my_event.set()65                my_event.set()
66        await my_event.wait()66        await my_event.wait()
n67        return self._task_index[task]n67        return self._task_slot[task]
6868
69    async def reset(self):69    async def reset(self):
t70        """t
71        Сбрасывает портал в исходное состояние.
72        Предполагается, что вызывается, когда никто не ждёт.
73        """
74        async with self._lock:70        async with self._mutex:
75            self._generation = 071            self._phase = 0
76            self._n_waiting = 072            self._count = 0
77            self._event = asyncio.Event()73            self._phase_event = asyncio.Event()
78            self._broken = False74            self._is_broken = False
79            self._topic = None75            self._last_topic = None
80            self._pending_topic.clear()76            self._phase_topics_pending.clear()
81            self._gen_topic.clear()77            self._phase_topics.clear()
82            self._task_gen.clear()78            self._task_phase.clear()
83            self._task_index.clear()79            self._task_slot.clear()
8480
85    async def __aenter__(self):81    async def __aenter__(self):
86        return await self.wait()82        return await self.wait()
8783
88    async def __aexit__(self, exc_type, exc, tb):84    async def __aexit__(self, exc_type, exc, tb):
89        return False85        return False
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op