Ticket #16679: no_cache_fast_signals.diff
File no_cache_fast_signals.diff, 6.4 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 if not a: 214 return b 215 elif not b: 216 return a 223 217 224 for (receiverkey, r_senderkey), receiver in self.receivers: 225 if r_senderkey == none_senderkey or r_senderkey == senderkey: 218 a_index = 0 219 b_index = 0 220 while a_index < len(a) and b_index < len(b): 221 if a[a_index][2] < b[b_index][2]: 222 yield a[a_index][1] 223 a_index += 1 224 else: 225 yield b[b_index][1] 226 b_index += 1 227 for i in range(a_index, len(a)): 228 yield a[i][1] 229 for i in range(b_index, len(b)): 230 yield b[i][1] 231 232 def deref(receivers): 233 for receiver in receivers: 226 234 if isinstance(receiver, WEAKREF_TYPES): 227 235 # Dereference the weak reference. 228 236 receiver = receiver() 229 237 if receiver is not None: 230 receivers.append(receiver)238 yield receiver 231 239 else: 232 receivers.append(receiver) 233 return receivers 240 yield receiver 234 241 235 def _remove_receiver(self, receiver): 242 receivers = combine(self.receivers[None], self.receivers[sender]) 243 return list(deref(receivers)) 244 245 def _remove_receiver(self, dead_receiver): 236 246 """ 237 247 Remove dead receivers from connections. 238 248 """ 239 249 240 250 self.lock.acquire() 241 251 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] 252 for receivers in self.receivers.values(): 253 for index, (key, receiver, _) in enumerate(receivers): 254 if receiver == dead_receiver: 255 del receivers[index] 253 256 finally: 254 257 self.lock.release() 255 258