Index: core/urlresolvers.py
===================================================================
--- core/urlresolvers.py	(revision 5468)
+++ core/urlresolvers.py	(working copy)
@@ -11,6 +11,25 @@
 from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist
 import re
 
+def cacheable(func, cache):
+    def wrapper(arg):
+        if arg in cache:
+            return cache[arg]
+        
+        result = func(arg)
+        cache[arg] = result
+        return result
+    return wrapper
+
+resolver_cache = {}
+
+def get_resolver(urlconf):
+    if urlconf is None:
+        from django.conf import settings
+        urlconf = settings.ROOT_URLCONF
+    return RegexURLResolver(r'^/', urlconf)
+get_resolver = cacheable(get_resolver, resolver_cache)
+
 class Resolver404(Http404):
     pass
 
@@ -160,6 +179,15 @@
         self.urlconf_name = urlconf_name
         self.callback = None
         self.default_kwargs = default_kwargs or {}
+        self.reverse_dict = {}
+        
+        for pattern in reversed(self.urlconf_module.urlpatterns):
+            if isinstance(pattern, RegexURLResolver):
+                for key, value in pattern.reverse_dict.iteritems():
+                    self.reverse_dict[key] = (pattern,) + value
+            else:
+                self.reverse_dict[pattern.callback] = (pattern,)
+                self.reverse_dict[pattern.name] = (pattern,)
 
     def resolve(self, path):
         tried = []
@@ -209,24 +237,10 @@
         return self._resolve_special('500')
 
     def reverse(self, lookup_view, *args, **kwargs):
-        if not callable(lookup_view):
-            mod_name, func_name = get_mod_func(lookup_view)
-            try:
-                lookup_view = getattr(__import__(mod_name, {}, {}, ['']), func_name)
-            except (ImportError, AttributeError):
-                if func_name != '':
-                    raise NoReverseMatch
-        for pattern in self.urlconf_module.urlpatterns:
-            if isinstance(pattern, RegexURLResolver):
-                try:
-                    return pattern.reverse_helper(lookup_view, *args, **kwargs)
-                except NoReverseMatch:
-                    continue
-            elif pattern.callback == lookup_view or pattern.name == lookup_view:
-                try:
-                    return pattern.reverse_helper(*args, **kwargs)
-                except NoReverseMatch:
-                    continue
+        lookup_view = make_callable(lookup_view)
+        if lookup_view in self.reverse_dict:
+            url_parts = (reverse_helper(part.regex, *args, **kwargs) for part in self.reverse_dict[lookup_view])
+            return ''.join(url_parts)
         raise NoReverseMatch
 
     def reverse_helper(self, lookup_view, *args, **kwargs):
@@ -234,18 +248,25 @@
         result = reverse_helper(self.regex, *args, **kwargs)
         return result + sub_match
 
+callable_cache = {}
+def make_callable(lookup_view):
+    if not callable(lookup_view):
+        mod_name, func_name = get_mod_func(lookup_view)
+        if func_name != '':
+            try:
+                lookup_view = getattr(__import__(mod_name, {}, {}, ['']), func_name)
+            except (ImportError, AttributeError):
+                if func_name != '':
+                    raise NoReverseMatch
+    return lookup_view
+make_callable = cacheable(make_callable, callable_cache)
+
 def resolve(path, urlconf=None):
-    if urlconf is None:
-        from django.conf import settings
-        urlconf = settings.ROOT_URLCONF
-    resolver = RegexURLResolver(r'^/', urlconf)
+    resolver = get_resolver(urlconf)
     return resolver.resolve(path)
 
 def reverse(viewname, urlconf=None, args=None, kwargs=None):
     args = args or []
     kwargs = kwargs or {}
-    if urlconf is None:
-        from django.conf import settings
-        urlconf = settings.ROOT_URLCONF
-    resolver = RegexURLResolver(r'^/', urlconf)
+    resolver = get_resolver(urlconf)
     return '/' + resolver.reverse(viewname, *args, **kwargs)
