1
1
from collections import deque , OrderedDict
2
2
from dataclasses import dataclass , field
3
- from typing import TypeVar , Generic , List , Deque , Tuple
3
+ from typing import TypeVar , Generic , List , Deque
4
4
5
5
from .. import get_cancelled_exc_class
6
6
from .._core ._lowlevel import checkpoint
@@ -18,7 +18,8 @@ class MemoryObjectStreamState(Generic[T_Item]):
18
18
buffer : Deque [T_Item ] = field (init = False , default_factory = deque )
19
19
open_send_channels : int = field (init = False , default = 0 )
20
20
open_receive_channels : int = field (init = False , default = 0 )
21
- waiting_receivers : Deque [Tuple [Event , List [T_Item ]]] = field (init = False , default_factory = deque )
21
+ waiting_receivers : 'OrderedDict[Event, List[T_Item]]' = field (init = False ,
22
+ default_factory = OrderedDict )
22
23
waiting_senders : 'OrderedDict[Event, T_Item]' = field (init = False , default_factory = OrderedDict )
23
24
24
25
@@ -66,34 +67,17 @@ async def receive(self) -> T_Item:
66
67
# Add ourselves in the queue
67
68
receive_event = create_event ()
68
69
container : List [T_Item ] = []
69
- ticket = receive_event , container
70
- self ._state .waiting_receivers .append (ticket )
70
+ self ._state .waiting_receivers [receive_event ] = container
71
71
72
72
try :
73
73
await receive_event .wait ()
74
74
except get_cancelled_exc_class ():
75
- # If we already received an item in the container, pass it to the next receiver in
76
- # line
77
- index = self ._state .waiting_receivers .index (ticket ) + 1
78
- if container :
79
- item = container [0 ]
80
- while index < len (self ._state .waiting_receivers ):
81
- receive_event , container = self ._state .waiting_receivers [index ]
82
- if container :
83
- item , container [0 ] = container [0 ], item
84
- else :
85
- # Found an untriggered receiver
86
- container .append (item )
87
- await receive_event .set ()
88
- break
89
- else :
90
- # Could not find an untriggered receiver, so in order to not lose any
91
- # items, put it in the buffer, even if it exceeds the maximum buffer size
92
- self ._state .buffer .append (item )
93
-
94
- raise
75
+ # Ignore the immediate cancellation if we already received an item, so as not to
76
+ # lose it
77
+ if not container :
78
+ raise
95
79
finally :
96
- self ._state .waiting_receivers .remove ( ticket )
80
+ self ._state .waiting_receivers .pop ( receive_event , None )
97
81
98
82
if container :
99
83
return container [0 ]
@@ -151,13 +135,11 @@ async def send_nowait(self, item: T_Item) -> None:
151
135
if not self ._state .open_receive_channels :
152
136
raise BrokenResourceError
153
137
154
- for receive_event , container in self ._state .waiting_receivers :
155
- if not container :
156
- container .append (item )
157
- await receive_event .set ()
158
- return
159
-
160
- if len (self ._state .buffer ) < self ._state .max_buffer_size :
138
+ if self ._state .waiting_receivers :
139
+ receive_event , container = self ._state .waiting_receivers .popitem (last = False )
140
+ container .append (item )
141
+ await receive_event .set ()
142
+ elif len (self ._state .buffer ) < self ._state .max_buffer_size :
161
143
self ._state .buffer .append (item )
162
144
else :
163
145
raise WouldBlock
@@ -199,6 +181,7 @@ async def aclose(self) -> None:
199
181
self ._closed = True
200
182
self ._state .open_send_channels -= 1
201
183
if self ._state .open_send_channels == 0 :
202
- receive_events = [event for event , container in self ._state .waiting_receivers ]
184
+ receive_events = list (self ._state .waiting_receivers .keys ())
185
+ self ._state .waiting_receivers .clear ()
203
186
for event in receive_events :
204
187
await event .set ()
0 commit comments