Ticket #16679: no_cache_fast_signals.diff

File no_cache_fast_signals.diff, 6.4 KB (added by Suor, 4 years ago)
  • django/dispatch/dispatcher.py

     
    11import weakref
    22import threading
     3from collections import defaultdict
    34
    45from django.dispatch import saferef
    56
     
    2728        providing_args
    2829            A list of the arguments this signal can pass along in a send() call.
    2930        """
    30         self.receivers = []
     31        self.receivers = defaultdict(list)
     32        self.connect_index = 0
    3133        if providing_args is None:
    3234            providing_args = []
    3335        self.providing_args = set(providing_args)
     
    9193                assert argspec[2] is not None, \
    9294                    "Signal receivers must accept keyword arguments (**kwargs)."
    9395       
    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)
    9897
    9998        if weak:
    10099            receiver = saferef.safeRef(receiver, onDelete=self._remove_receiver)
    101100
    102101        self.lock.acquire()
    103102        try:
    104             for r_key, _ in self.receivers:
    105                 if r_key == lookup_key:
    106                     break
    107             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
    109108        finally:
    110109            self.lock.release()
    111110
     
    131130            dispatch_uid
    132131                the unique identifier of the receiver to disconnect
    133132        """
    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)
    138134       
    139135        self.lock.acquire()
    140136        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]
    145140                    break
    146141        finally:
    147142            self.lock.release()
     
    165160        Returns a list of tuple pairs [(receiver, response), ... ].
    166161        """
    167162        responses = []
    168         if not self.receivers:
    169             return responses
    170163
    171         for receiver in self._live_receivers(_make_id(sender)):
     164        for receiver in self._live_receivers(sender):
    172165            response = receiver(signal=self, sender=sender, **named)
    173166            responses.append((receiver, response))
    174167        return responses
     
    197190        receiver.
    198191        """
    199192        responses = []
    200         if not self.receivers:
    201             return responses
    202193
    203194        # Call each receiver with whatever arguments it can accept.
    204195        # 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):
    206197            try:
    207198                response = receiver(signal=self, sender=sender, **named)
    208199            except Exception, err:
     
    211202                responses.append((receiver, response))
    212203        return responses
    213204
    214     def _live_receivers(self, senderkey):
     205    def _live_receivers(self, sender):
    215206        """
    216         Filter sequence of receivers to get resolved, live receivers.
     207        Construct sequence of receivers to get resolved, live receivers.
    217208
    218209        This checks for weak references and resolves them, then returning only
    219210        live receivers.
    220211        """
    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
    223217
    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:
    226234                if isinstance(receiver, WEAKREF_TYPES):
    227235                    # Dereference the weak reference.
    228236                    receiver = receiver()
    229237                    if receiver is not None:
    230                         receivers.append(receiver)
     238                        yield receiver
    231239                else:
    232                     receivers.append(receiver)
    233         return receivers
     240                    yield receiver
    234241
    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):
    236246        """
    237247        Remove dead receivers from connections.
    238248        """
    239249
    240250        self.lock.acquire()
    241251        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]
    253256        finally:
    254257            self.lock.release()
    255258
Back to Top