Ticket #16679: fast-signals1.diff

File fast-signals1.diff, 5.4 KB (added by akaariai, 4 years ago)

Without sender -> receivers cache

  • django/db/models/base.py

    diff --git a/django/db/models/base.py b/django/db/models/base.py
    index 71fd1f7..730e52f 100644
    a b from django.db.models.query_utils import DeferredAttribute 
    1818from django.db.models.deletion import Collector
    1919from django.db.models.options import Options
    2020from django.db.models import signals
     21from django.db.models.signals import pre_init, post_init
    2122from django.db.models.loading import register_models, get_model
    2223from django.utils.translation import ugettext_lazy as _
    2324from django.utils.functional import curry
    class Model(object): 
    277278    _deferred = False
    278279
    279280    def __init__(self, *args, **kwargs):
    280         signals.pre_init.send(sender=self.__class__, args=args, kwargs=kwargs)
     281        pre_init.send(sender=self.__class__, args=args, kwargs=kwargs)
    281282
    282283        # Set up the storage for instance state
    283284        self._state = ModelState()
    class Model(object): 
    367368            if kwargs:
    368369                raise TypeError("'%s' is an invalid keyword argument for this function" % kwargs.keys()[0])
    369370        super(Model, self).__init__()
    370         signals.post_init.send(sender=self.__class__, instance=self)
     371        post_init.send(sender=self.__class__, instance=self)
    371372
    372373    def __repr__(self):
    373374        try:
  • django/dispatch/dispatcher.py

    diff --git a/django/dispatch/dispatcher.py b/django/dispatch/dispatcher.py
    index ed9da57..989d86d 100644
    a b class Signal(object): 
    3131        if providing_args is None:
    3232            providing_args = []
    3333        self.providing_args = set(providing_args)
     34        self.sender_no_receivers_cache = set()
    3435        self.lock = threading.Lock()
    3536
    3637    def connect(self, receiver, sender=None, weak=True, dispatch_uid=None):
    class Signal(object): 
    107108            else:
    108109                self.receivers.append((lookup_key, receiver))
    109110        finally:
     111            self.sender_no_receivers_cache = set()
    110112            self.lock.release()
    111113
    112114    def disconnect(self, receiver=None, sender=None, weak=True, dispatch_uid=None):
    class Signal(object): 
    144146                    del self.receivers[index]
    145147                    break
    146148        finally:
     149            self.sender_no_receivers_cache = set()
    147150            self.lock.release()
    148151
    149152    def send(self, sender, **named):
    class Signal(object): 
    165168        Returns a list of tuple pairs [(receiver, response), ... ].
    166169        """
    167170        responses = []
    168         if not self.receivers:
     171        if sender in self.sender_no_receivers_cache:
    169172            return responses
    170173
    171         for receiver in self._live_receivers(_make_id(sender)):
     174        for receiver in self._live_receivers(sender):
    172175            response = receiver(signal=self, sender=sender, **named)
    173176            responses.append((receiver, response))
    174177        return responses
    class Signal(object): 
    197200        receiver.
    198201        """
    199202        responses = []
    200         if not self.receivers:
     203        if sender in self.sender_no_receivers_cache:
    201204            return responses
    202205
    203206        # Call each receiver with whatever arguments it can accept.
    204207        # Return a list of tuple pairs [(receiver, response), ... ].
    205         for receiver in self._live_receivers(_make_id(sender)):
     208        for receiver in self._live_receivers(sender):
    206209            try:
    207210                response = receiver(signal=self, sender=sender, **named)
    208211            except Exception, err:
    class Signal(object): 
    211214                responses.append((receiver, response))
    212215        return responses
    213216
    214     def _live_receivers(self, senderkey):
     217    def _live_receivers(self, sender):
    215218        """
    216219        Filter sequence of receivers to get resolved, live receivers.
    217220
    class Signal(object): 
    219222        live receivers.
    220223        """
    221224        none_senderkey = _make_id(None)
     225        senderkey = _make_id(sender)
    222226        receivers = []
    223 
     227        # Here is a trick which I believe is safe, but I haven't actually
     228        # proved it. We store a reference to current sender_no_receivers_cache
     229        # If there are modifications to self.receivers, then the
     230        # modifier will create a new object for self.sender_no_receivers.
     231        # Thus, if we decide to store something in local_sender_no_receivers
     232        # cache using stale self.receivers info, there is no harm, because
     233        # the reference itself is stale! Of course, this needs a more
     234        # convincing comment, or maybe a proof...
     235        local_sender_no_receivers = self.sender_no_receivers_cache
    224236        for (receiverkey, r_senderkey), receiver in self.receivers:
    225237            if r_senderkey == none_senderkey or r_senderkey == senderkey:
    226238                if isinstance(receiver, WEAKREF_TYPES):
    class Signal(object): 
    230242                        receivers.append(receiver)
    231243                else:
    232244                    receivers.append(receiver)
     245        if not receivers:
     246            local_sender_no_receivers.add(sender)
    233247        return receivers
    234248
    235249    def _remove_receiver(self, receiver):
    236250        """
    237251        Remove dead receivers from connections.
    238252        """
    239 
    240253        self.lock.acquire()
    241254        try:
    242255            to_remove = []
    class Signal(object): 
    251264                    if r_key == key:
    252265                        del self.receivers[last_idx-idx]
    253266        finally:
     267            self.sender_no_receivers_cache = set()
    254268            self.lock.release()
    255269
    256270
Back to Top