Ticket #16679: no_cache_fast_signals.3.diff

File no_cache_fast_signals.3.diff, 6.6 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            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]
     218                    a_index += 1
     219                else:
     220                    yield b[b_index]
     221                    b_index += 1
     222            for i in range(a_index, len(a)):
     223                yield a[i]
     224            for i in range(b_index, len(b)):
     225                yield b[i]
    223226
    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:
    226229                if isinstance(receiver, WEAKREF_TYPES):
    227230                    # Dereference the weak reference.
    228231                    receiver = receiver()
    229232                    if receiver is not None:
    230                         receivers.append(receiver)
     233                        yield receiver
    231234                else:
    232                     receivers.append(receiver)
    233         return receivers
     235                    yield receiver
    234236
    235     def _remove_receiver(self, receiver):
     237        if not self.receivers[None]:
     238            receivers = self.receivers[sender]
     239        elif not self.receivers[sender] or sender is None:
     240            receivers = self.receivers[None]
     241        else:
     242            receivers = combine(self.receivers[None], self.receivers[sender])
     243
     244        if not receivers:
     245            return []
     246
     247        return list(deref(receivers))
     248
     249    def _remove_receiver(self, dead_receiver):
    236250        """
    237251        Remove dead receivers from connections.
    238252        """
    239253
    240254        self.lock.acquire()
    241255        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]
     256            for receivers in self.receivers.values():
     257                for index, (key, receiver, _) in enumerate(receivers):
     258                    if receiver == dead_receiver:
     259                        del receivers[index]
    253260        finally:
    254261            self.lock.release()
    255262
Back to Top