Ticket #16679: no_cache_fast_signals.2.diff
File no_cache_fast_signals.2.diff, 6.3 KB (added by , 13 years ago) |
---|
-
django/dispatch/dispatcher.py
1 1 import weakref 2 2 import threading 3 from collections import defaultdict 3 4 4 5 from django.dispatch import saferef 5 6 … … 27 28 providing_args 28 29 A list of the arguments this signal can pass along in a send() call. 29 30 """ 30 self.receivers = [] 31 self.receivers = defaultdict(list) 32 self.connect_index = 0 31 33 if providing_args is None: 32 34 providing_args = [] 33 35 self.providing_args = set(providing_args) … … 91 93 assert argspec[2] is not None, \ 92 94 "Signal receivers must accept keyword arguments (**kwargs)." 93 95 94 if dispatch_uid: 95 lookup_key = (dispatch_uid, _make_id(sender)) 96 else: 97 lookup_key = (_make_id(receiver), _make_id(sender)) 96 lookup_key = dispatch_uid or _make_id(receiver) 98 97 99 98 if weak: 100 99 receiver = saferef.safeRef(receiver, onDelete=self._remove_receiver) 101 100 102 101 self.lock.acquire() 103 102 try: 104 for r_key, _ in self.receivers:105 if r_key == lookup_key:106 break107 else:108 self. receivers.append((lookup_key, receiver))103 # Should really use OrderedDict in python 2.7 104 registered_keys = (rec[1] for rec in self.receivers[sender]) 105 if lookup_key not in registered_keys: 106 self.receivers[sender].append((lookup_key, receiver, self.connect_index)) 107 self.connect_index += 1 109 108 finally: 110 109 self.lock.release() 111 110 … … 131 130 dispatch_uid 132 131 the unique identifier of the receiver to disconnect 133 132 """ 134 if dispatch_uid: 135 lookup_key = (dispatch_uid, _make_id(sender)) 136 else: 137 lookup_key = (_make_id(receiver), _make_id(sender)) 133 lookup_key = dispatch_uid or _make_id(receiver) 138 134 139 135 self.lock.acquire() 140 136 try: 141 for index in xrange(len(self.receivers)): 142 (r_key, _) = self.receivers[index] 143 if r_key == lookup_key: 144 del self.receivers[index] 137 for index, (key, _, _) in enumerate(self.receivers[sender]): 138 if key == lookup_key: 139 del self.receivers[sender][index] 145 140 break 146 141 finally: 147 142 self.lock.release() … … 165 160 Returns a list of tuple pairs [(receiver, response), ... ]. 166 161 """ 167 162 responses = [] 168 if not self.receivers:169 return responses170 163 171 for receiver in self._live_receivers( _make_id(sender)):164 for receiver in self._live_receivers(sender): 172 165 response = receiver(signal=self, sender=sender, **named) 173 166 responses.append((receiver, response)) 174 167 return responses … … 197 190 receiver. 198 191 """ 199 192 responses = [] 200 if not self.receivers:201 return responses202 193 203 194 # Call each receiver with whatever arguments it can accept. 204 195 # Return a list of tuple pairs [(receiver, response), ... ]. 205 for receiver in self._live_receivers( _make_id(sender)):196 for receiver in self._live_receivers(sender): 206 197 try: 207 198 response = receiver(signal=self, sender=sender, **named) 208 199 except Exception, err: … … 211 202 responses.append((receiver, response)) 212 203 return responses 213 204 214 def _live_receivers(self, sender key):205 def _live_receivers(self, sender): 215 206 """ 216 Filtersequence of receivers to get resolved, live receivers.207 Construct sequence of receivers to get resolved, live receivers. 217 208 218 209 This checks for weak references and resolves them, then returning only 219 210 live receivers. 220 211 """ 221 none_senderkey = _make_id(None) 222 receivers = [] 212 def combine(a, b): 213 a_index = 0 214 b_index = 0 215 while a_index < len(a) and b_index < len(b): 216 if a[a_index][2] < b[b_index][2]: 217 yield a[a_index][1] 218 a_index += 1 219 else: 220 yield b[b_index][1] 221 b_index += 1 222 for i in range(a_index, len(a)): 223 yield a[i][1] 224 for i in range(b_index, len(b)): 225 yield b[i][1] 223 226 224 for (receiverkey, r_senderkey), receiver in self.receivers:225 if r_senderkey == none_senderkey or r_senderkey == senderkey:227 def deref(receivers): 228 for receiver in receivers: 226 229 if isinstance(receiver, WEAKREF_TYPES): 227 230 # Dereference the weak reference. 228 231 receiver = receiver() 229 232 if receiver is not None: 230 receivers.append(receiver)233 yield receiver 231 234 else: 232 receivers.append(receiver) 233 return receivers 235 yield receiver 234 236 235 def _remove_receiver(self, receiver): 237 receivers = combine(self.receivers[None], self.receivers[sender]) 238 return list(deref(receivers)) 239 240 def _remove_receiver(self, dead_receiver): 236 241 """ 237 242 Remove dead receivers from connections. 238 243 """ 239 244 240 245 self.lock.acquire() 241 246 try: 242 to_remove = [] 243 for key, connected_receiver in self.receivers: 244 if connected_receiver == receiver: 245 to_remove.append(key) 246 for key in to_remove: 247 last_idx = len(self.receivers) - 1 248 # enumerate in reverse order so that indexes are valid even 249 # after we delete some items 250 for idx, (r_key, _) in enumerate(reversed(self.receivers)): 251 if r_key == key: 252 del self.receivers[last_idx-idx] 247 for receivers in self.receivers.values(): 248 for index, (key, receiver, _) in enumerate(receivers): 249 if receiver == dead_receiver: 250 del receivers[index] 253 251 finally: 254 252 self.lock.release() 255 253