Index: django/dispatch/dispatcher.py
===================================================================
--- django/dispatch/dispatcher.py	(revision 16928)
+++ django/dispatch/dispatcher.py	(working copy)
@@ -1,5 +1,6 @@
 import weakref
 import threading
+from collections import defaultdict
 
 from django.dispatch import saferef
 
@@ -27,7 +28,8 @@
         providing_args
             A list of the arguments this signal can pass along in a send() call.
         """
-        self.receivers = []
+        self.receivers = defaultdict(list)
+        self.connect_index = 0
         if providing_args is None:
             providing_args = []
         self.providing_args = set(providing_args)
@@ -91,21 +93,18 @@
                 assert argspec[2] is not None, \
                     "Signal receivers must accept keyword arguments (**kwargs)."
         
-        if dispatch_uid:
-            lookup_key = (dispatch_uid, _make_id(sender))
-        else:
-            lookup_key = (_make_id(receiver), _make_id(sender))
+        lookup_key = dispatch_uid or _make_id(receiver)
 
         if weak:
             receiver = saferef.safeRef(receiver, onDelete=self._remove_receiver)
 
         self.lock.acquire()
         try:
-            for r_key, _ in self.receivers:
-                if r_key == lookup_key:
-                    break
-            else:
-                self.receivers.append((lookup_key, receiver))
+            # Should really use OrderedDict in python 2.7
+            registered_keys = (rec[1] for rec in self.receivers[sender])
+            if lookup_key not in registered_keys:
+                self.receivers[sender].append((lookup_key, receiver, self.connect_index))
+                self.connect_index += 1
         finally:
             self.lock.release()
 
@@ -131,17 +130,13 @@
             dispatch_uid
                 the unique identifier of the receiver to disconnect
         """
-        if dispatch_uid:
-            lookup_key = (dispatch_uid, _make_id(sender))
-        else:
-            lookup_key = (_make_id(receiver), _make_id(sender))
+        lookup_key = dispatch_uid or _make_id(receiver)
         
         self.lock.acquire()
         try:
-            for index in xrange(len(self.receivers)):
-                (r_key, _) = self.receivers[index]
-                if r_key == lookup_key:
-                    del self.receivers[index]
+            for index, (key, _, _) in enumerate(self.receivers[sender]):
+                if key == lookup_key:
+                    del self.receivers[sender][index]
                     break
         finally:
             self.lock.release()
@@ -165,10 +160,8 @@
         Returns a list of tuple pairs [(receiver, response), ... ].
         """
         responses = []
-        if not self.receivers:
-            return responses
 
-        for receiver in self._live_receivers(_make_id(sender)):
+        for receiver in self._live_receivers(sender):
             response = receiver(signal=self, sender=sender, **named)
             responses.append((receiver, response))
         return responses
@@ -197,12 +190,10 @@
         receiver.
         """
         responses = []
-        if not self.receivers:
-            return responses
 
         # Call each receiver with whatever arguments it can accept.
         # Return a list of tuple pairs [(receiver, response), ... ].
-        for receiver in self._live_receivers(_make_id(sender)):
+        for receiver in self._live_receivers(sender):
             try:
                 response = receiver(signal=self, sender=sender, **named)
             except Exception, err:
@@ -211,45 +202,52 @@
                 responses.append((receiver, response))
         return responses
 
-    def _live_receivers(self, senderkey):
+    def _live_receivers(self, sender):
         """
-        Filter sequence of receivers to get resolved, live receivers.
+        Construct sequence of receivers to get resolved, live receivers.
 
         This checks for weak references and resolves them, then returning only
         live receivers.
         """
-        none_senderkey = _make_id(None)
-        receivers = []
+        def combine(a, b):
+            a_index = 0
+            b_index = 0
+            while a_index < len(a) and b_index < len(b):
+                if a[a_index][2] < b[b_index][2]:
+                    yield a[a_index][1]
+                    a_index += 1
+                else:
+                    yield b[b_index][1]
+                    b_index += 1
+            for i in range(a_index, len(a)):
+                yield a[i][1]
+            for i in range(b_index, len(b)):
+                yield b[i][1]
 
-        for (receiverkey, r_senderkey), receiver in self.receivers:
-            if r_senderkey == none_senderkey or r_senderkey == senderkey:
+        def deref(receivers):
+            for receiver in receivers:
                 if isinstance(receiver, WEAKREF_TYPES):
                     # Dereference the weak reference.
                     receiver = receiver()
                     if receiver is not None:
-                        receivers.append(receiver)
+                        yield receiver
                 else:
-                    receivers.append(receiver)
-        return receivers
+                    yield receiver
 
-    def _remove_receiver(self, receiver):
+        receivers = combine(self.receivers[None], self.receivers[sender])
+        return list(deref(receivers))
+
+    def _remove_receiver(self, dead_receiver):
         """
         Remove dead receivers from connections.
         """
 
         self.lock.acquire()
         try:
-            to_remove = []
-            for key, connected_receiver in self.receivers:
-                if connected_receiver == receiver:
-                    to_remove.append(key)
-            for key in to_remove:
-                last_idx = len(self.receivers) - 1
-                # enumerate in reverse order so that indexes are valid even
-                # after we delete some items
-                for idx, (r_key, _) in enumerate(reversed(self.receivers)):
-                    if r_key == key:
-                        del self.receivers[last_idx-idx]
+            for receivers in self.receivers.values():
+                for index, (key, receiver, _) in enumerate(receivers):
+                    if receiver == dead_receiver:
+                        del receivers[index]
         finally:
             self.lock.release()
 
