Code

Ticket #16679: no_cache_fast_signals.3.diff

File no_cache_fast_signals.3.diff, 6.6 KB (added by Suor, 3 years ago)
Line 
1Index: django/dispatch/dispatcher.py
2===================================================================
3--- django/dispatch/dispatcher.py       (revision 16928)
4+++ django/dispatch/dispatcher.py       (working copy)
5@@ -1,5 +1,6 @@
6 import weakref
7 import threading
8+from collections import defaultdict
9 
10 from django.dispatch import saferef
11 
12@@ -27,7 +28,8 @@
13         providing_args
14             A list of the arguments this signal can pass along in a send() call.
15         """
16-        self.receivers = []
17+        self.receivers = defaultdict(list)
18+        self.connect_index = 0
19         if providing_args is None:
20             providing_args = []
21         self.providing_args = set(providing_args)
22@@ -91,21 +93,18 @@
23                 assert argspec[2] is not None, \
24                     "Signal receivers must accept keyword arguments (**kwargs)."
25         
26-        if dispatch_uid:
27-            lookup_key = (dispatch_uid, _make_id(sender))
28-        else:
29-            lookup_key = (_make_id(receiver), _make_id(sender))
30+        lookup_key = dispatch_uid or _make_id(receiver)
31 
32         if weak:
33             receiver = saferef.safeRef(receiver, onDelete=self._remove_receiver)
34 
35         self.lock.acquire()
36         try:
37-            for r_key, _ in self.receivers:
38-                if r_key == lookup_key:
39-                    break
40-            else:
41-                self.receivers.append((lookup_key, receiver))
42+            # Should really use OrderedDict in python 2.7
43+            registered_keys = (rec[1] for rec in self.receivers[sender])
44+            if lookup_key not in registered_keys:
45+                self.receivers[sender].append((lookup_key, receiver, self.connect_index))
46+                self.connect_index += 1
47         finally:
48             self.lock.release()
49 
50@@ -131,17 +130,13 @@
51             dispatch_uid
52                 the unique identifier of the receiver to disconnect
53         """
54-        if dispatch_uid:
55-            lookup_key = (dispatch_uid, _make_id(sender))
56-        else:
57-            lookup_key = (_make_id(receiver), _make_id(sender))
58+        lookup_key = dispatch_uid or _make_id(receiver)
59         
60         self.lock.acquire()
61         try:
62-            for index in xrange(len(self.receivers)):
63-                (r_key, _) = self.receivers[index]
64-                if r_key == lookup_key:
65-                    del self.receivers[index]
66+            for index, (key, _, _) in enumerate(self.receivers[sender]):
67+                if key == lookup_key:
68+                    del self.receivers[sender][index]
69                     break
70         finally:
71             self.lock.release()
72@@ -165,10 +160,8 @@
73         Returns a list of tuple pairs [(receiver, response), ... ].
74         """
75         responses = []
76-        if not self.receivers:
77-            return responses
78 
79-        for receiver in self._live_receivers(_make_id(sender)):
80+        for receiver in self._live_receivers(sender):
81             response = receiver(signal=self, sender=sender, **named)
82             responses.append((receiver, response))
83         return responses
84@@ -197,12 +190,10 @@
85         receiver.
86         """
87         responses = []
88-        if not self.receivers:
89-            return responses
90 
91         # Call each receiver with whatever arguments it can accept.
92         # Return a list of tuple pairs [(receiver, response), ... ].
93-        for receiver in self._live_receivers(_make_id(sender)):
94+        for receiver in self._live_receivers(sender):
95             try:
96                 response = receiver(signal=self, sender=sender, **named)
97             except Exception, err:
98@@ -211,45 +202,61 @@
99                 responses.append((receiver, response))
100         return responses
101 
102-    def _live_receivers(self, senderkey):
103+    def _live_receivers(self, sender):
104         """
105-        Filter sequence of receivers to get resolved, live receivers.
106+        Construct sequence of receivers to get resolved, live receivers.
107 
108         This checks for weak references and resolves them, then returning only
109         live receivers.
110         """
111-        none_senderkey = _make_id(None)
112-        receivers = []
113+        def combine(a, b):
114+            a_index = 0
115+            b_index = 0
116+            while a_index < len(a) and b_index < len(b):
117+                if a[a_index][2] < b[b_index][2]:
118+                    yield a[a_index]
119+                    a_index += 1
120+                else:
121+                    yield b[b_index]
122+                    b_index += 1
123+            for i in range(a_index, len(a)):
124+                yield a[i]
125+            for i in range(b_index, len(b)):
126+                yield b[i]
127 
128-        for (receiverkey, r_senderkey), receiver in self.receivers:
129-            if r_senderkey == none_senderkey or r_senderkey == senderkey:
130+        def deref(receivers):
131+            for _, receiver, _ in receivers:
132                 if isinstance(receiver, WEAKREF_TYPES):
133                     # Dereference the weak reference.
134                     receiver = receiver()
135                     if receiver is not None:
136-                        receivers.append(receiver)
137+                        yield receiver
138                 else:
139-                    receivers.append(receiver)
140-        return receivers
141+                    yield receiver
142 
143-    def _remove_receiver(self, receiver):
144+        if not self.receivers[None]:
145+            receivers = self.receivers[sender]
146+        elif not self.receivers[sender] or sender is None:
147+            receivers = self.receivers[None]
148+        else:
149+            receivers = combine(self.receivers[None], self.receivers[sender])
150+
151+        if not receivers:
152+            return []
153+
154+        return list(deref(receivers))
155+
156+    def _remove_receiver(self, dead_receiver):
157         """
158         Remove dead receivers from connections.
159         """
160 
161         self.lock.acquire()
162         try:
163-            to_remove = []
164-            for key, connected_receiver in self.receivers:
165-                if connected_receiver == receiver:
166-                    to_remove.append(key)
167-            for key in to_remove:
168-                last_idx = len(self.receivers) - 1
169-                # enumerate in reverse order so that indexes are valid even
170-                # after we delete some items
171-                for idx, (r_key, _) in enumerate(reversed(self.receivers)):
172-                    if r_key == key:
173-                        del self.receivers[last_idx-idx]
174+            for receivers in self.receivers.values():
175+                for index, (key, receiver, _) in enumerate(receivers):
176+                    if receiver == dead_receiver:
177+                        del receivers[index]
178         finally:
179             self.lock.release()
180