-
-
Notifications
You must be signed in to change notification settings - Fork 32.6k
Fixed #35518 -- Used simpler string operations for converter-less routes #18270
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fixed #35518 -- Used simpler string operations for converter-less routes #18270
Conversation
9416613
to
b0bbb03
Compare
b0bbb03
to
762890b
Compare
762890b
to
35e8166
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
I added code suggestions to compact a bit the code.
django/urls/resolvers.py
Outdated
|
||
# If there are no converters, skip the regex overhead and | ||
# use string operations | ||
|
||
# If this is an endpoint, the path should be | ||
# exactly the same as the route | ||
elif self._is_endpoint: | ||
if self._route == path: | ||
return "", (), {} | ||
|
||
# If this isn't an endpoint, the path should start with the route | ||
elif path.startswith(self._route): | ||
return path.removeprefix(self._route), (), {} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# If there are no converters, skip the regex overhead and | |
# use string operations | |
# If this is an endpoint, the path should be | |
# exactly the same as the route | |
elif self._is_endpoint: | |
if self._route == path: | |
return "", (), {} | |
# If this isn't an endpoint, the path should start with the route | |
elif path.startswith(self._route): | |
return path.removeprefix(self._route), (), {} | |
# If there are no converters, skip the regex overhead and use string operations | |
# If this is an endpoint, the path should be exactly the same as the route | |
elif self._is_endpoint: | |
if self._route == path: | |
return "", (), {} | |
# If this isn't an endpoint, the path should start with the route | |
elif path.startswith(self._route): | |
return path.removeprefix(self._route), (), {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I disagree - the extra newlines break up each condition, and make it clearer what the comment is for.
tests/urlpatterns/test_resolvers.py
Outdated
def test_has_converters(self): | ||
self.assertEqual(len(RoutePattern("translated/").converters), 0) | ||
self.assertEqual(len(RoutePattern(_("translated/")).converters), 0) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
35e8166
to
0827338
Compare
I've added some more benchmarks to the ticket which make the gain clearer. |
… converter-less routes.
0827338
to
07897da
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you!
Trac ticket number
ticket-35518
Branch description
The
RoutePattern
assumes all routes provided include some form of converter, and so needs to change it into a regex for matching. However, if no converters are included in the string, the additional overhead of using a regex vs simpler string operations is unnecessary.Replacing this with a simpler string comparison results in between a 50 and 75% reduction in match time, which stacks up quickly as an application generally has numerous URLs, because
RoutePattern.match
is called once per defined route per request.Before
After
(Benchmarked on Python 3.12, running
main
)Theoretically, these improvements get better based on the length of the route pattern (although at this scale, not notably).
This optimisation could be done by adding a different kind of pattern (eg
LiteralPattern
), but the added complexity to a project probably isn't necessary, not to mention the migration effort to take advantage of this.Checklist
main
branch.