diff --git a/django/db/models/base.py b/django/db/models/base.py
index 71fd1f7..730e52f 100644
--- a/django/db/models/base.py
+++ b/django/db/models/base.py
@@ -18,6 +18,7 @@ from django.db.models.query_utils import DeferredAttribute
 from django.db.models.deletion import Collector
 from django.db.models.options import Options
 from django.db.models import signals
+from django.db.models.signals import pre_init, post_init
 from django.db.models.loading import register_models, get_model
 from django.utils.translation import ugettext_lazy as _
 from django.utils.functional import curry
@@ -277,7 +278,7 @@ class Model(object):
     _deferred = False
 
     def __init__(self, *args, **kwargs):
-        signals.pre_init.send(sender=self.__class__, args=args, kwargs=kwargs)
+        pre_init.send(sender=self.__class__, args=args, kwargs=kwargs)
 
         # Set up the storage for instance state
         self._state = ModelState()
@@ -367,7 +368,7 @@ class Model(object):
             if kwargs:
                 raise TypeError("'%s' is an invalid keyword argument for this function" % kwargs.keys()[0])
         super(Model, self).__init__()
-        signals.post_init.send(sender=self.__class__, instance=self)
+        post_init.send(sender=self.__class__, instance=self)
 
     def __repr__(self):
         try:
diff --git a/django/db/models/signals.py b/django/db/models/signals.py
index 48872e7..65e8f23 100644
--- a/django/db/models/signals.py
+++ b/django/db/models/signals.py
@@ -2,15 +2,15 @@ from django.dispatch import Signal
 
 class_prepared = Signal(providing_args=["class"])
 
-pre_init = Signal(providing_args=["instance", "args", "kwargs"])
-post_init = Signal(providing_args=["instance"])
+pre_init = Signal(providing_args=["instance", "args", "kwargs"], use_caching=True)
+post_init = Signal(providing_args=["instance"], use_caching=True)
 
-pre_save = Signal(providing_args=["instance", "raw", "using"])
-post_save = Signal(providing_args=["instance", "raw", "created", "using"])
+pre_save = Signal(providing_args=["instance", "raw", "using"], use_caching=True)
+post_save = Signal(providing_args=["instance", "raw", "created", "using"], use_caching=True)
 
-pre_delete = Signal(providing_args=["instance", "using"])
-post_delete = Signal(providing_args=["instance", "using"])
+pre_delete = Signal(providing_args=["instance", "using"], use_caching=True)
+post_delete = Signal(providing_args=["instance", "using"], use_caching=True)
 
-post_syncdb = Signal(providing_args=["class", "app", "created_models", "verbosity", "interactive"])
+post_syncdb = Signal(providing_args=["class", "app", "created_models", "verbosity", "interactive"], use_caching=True)
 
-m2m_changed = Signal(providing_args=["action", "instance", "reverse", "model", "pk_set", "using"])
+m2m_changed = Signal(providing_args=["action", "instance", "reverse", "model", "pk_set", "using"], use_caching=True)
diff --git a/django/dispatch/dispatcher.py b/django/dispatch/dispatcher.py
index ed9da57..bd9e461 100644
--- a/django/dispatch/dispatcher.py
+++ b/django/dispatch/dispatcher.py
@@ -9,6 +9,7 @@ def _make_id(target):
     if hasattr(target, 'im_func'):
         return (id(target.im_self), id(target.im_func))
     return id(target)
+NONE_ID = _make_id(None)
 
 class Signal(object):
     """
@@ -20,7 +21,7 @@ class Signal(object):
             { receriverkey (id) : weakref(receiver) }
     """
     
-    def __init__(self, providing_args=None):
+    def __init__(self, providing_args=None, use_caching=False):
         """
         Create a new signal.
         
@@ -31,6 +32,10 @@ class Signal(object):
         if providing_args is None:
             providing_args = []
         self.providing_args = set(providing_args)
+        self.use_caching = use_caching
+        # For convenience we create empty caches even if they are not used
+        self.sender_no_receivers_cache = set()
+        self.sender_receivers_cache = {}
         self.lock = threading.Lock()
 
     def connect(self, receiver, sender=None, weak=True, dispatch_uid=None):
@@ -107,6 +112,9 @@ class Signal(object):
             else:
                 self.receivers.append((lookup_key, receiver))
         finally:
+            if self.use_caching:
+                self.sender_no_receivers_cache = set()
+                self.sender_receivers_cache = {}
             self.lock.release()
 
     def disconnect(self, receiver=None, sender=None, weak=True, dispatch_uid=None):
@@ -144,6 +152,9 @@ class Signal(object):
                     del self.receivers[index]
                     break
         finally:
+            if self.use_caching:
+               self.sender_no_receivers_cache = set()
+               self.sender_receivers_cache = {}
             self.lock.release()
 
     def send(self, sender, **named):
@@ -165,10 +176,10 @@ class Signal(object):
         Returns a list of tuple pairs [(receiver, response), ... ].
         """
         responses = []
-        if not self.receivers:
+        if not self.receivers or (self.use_caching and sender in self.sender_no_receivers_cache):
             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 +208,12 @@ class Signal(object):
         receiver.
         """
         responses = []
-        if not self.receivers:
+        if not self.receivers or (self.use_caching and sender in self.sender_no_receivers_cache):
             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,32 +222,46 @@ class Signal(object):
                 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.
 
         This checks for weak references and resolves them, then returning only
         live receivers.
         """
-        none_senderkey = _make_id(None)
-        receivers = []
-
-        for (receiverkey, r_senderkey), receiver in self.receivers:
-            if r_senderkey == none_senderkey or r_senderkey == senderkey:
-                if isinstance(receiver, WEAKREF_TYPES):
-                    # Dereference the weak reference.
-                    receiver = receiver()
-                    if receiver is not None:
-                        receivers.append(receiver)
-                else:
+        receivers = None
+        if self.use_caching:
+            receivers = self.sender_receivers_cache.get(sender)
+        if receivers is None:
+            none_senderkey = NONE_ID
+            senderkey = _make_id(sender)
+            receivers = []
+            if self.use_caching:
+                self.lock.acquire()
+            for (receiverkey, r_senderkey), receiver in self.receivers:
+                if r_senderkey == none_senderkey or r_senderkey == senderkey:
                     receivers.append(receiver)
-        return receivers
+            if self.use_caching:
+                if not receivers:
+                    self.sender_no_receivers_cache.add(sender)
+                # Note, we must cache the weakref versions.
+                self.sender_receivers_cache[sender] = receivers
+                self.lock.release()
+        non_weak_receivers = [] 
+        for receiver in receivers:
+            if isinstance(receiver, WEAKREF_TYPES):
+                # Dereference the weak reference.
+                receiver = receiver()
+                if receiver is not None:
+                    non_weak_receivers.append(receiver)
+            else:
+                non_weak_receivers.append(receiver)
+        return non_weak_receivers
 
     def _remove_receiver(self, receiver):
         """
         Remove dead receivers from connections.
         """
-
         self.lock.acquire()
         try:
             to_remove = []
@@ -251,6 +276,9 @@ class Signal(object):
                     if r_key == key:
                         del self.receivers[last_idx-idx]
         finally:
+            if self.use_caching:
+                self.sender_no_receivers_cache = set()
+                self.sender_receivers_cache = {}
             self.lock.release()
 
 
