Skip to content

Implement HttpRequest proxying with __getattr__ for optimized access. #5576

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

Closed
wants to merge 2 commits into from

Conversation

yotamofek
Copy link

I was profiling our production server and notices that quite a lot of the time it took for our ListSerializer.to_representation to run was in Request.__getattribute__.

The way __getattribute__ was implemented was catching AttributeError exceptions, which becomes quite a bottleneck when handling thousands of these exceptions for every request. Catching exceptions is expensive. Fortunately, __getattr__ is the interpreter-optimized way of doing the exact same thing. I made sure to keep the same traceback in the case of a true AttributeError.

On our production server, this change sped up certain requests by about 0.4 seconds, which is a large percent of a request that takes ~3 seconds to process.

Copy link
Collaborator

@carltongibson carltongibson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@yotamofek Looks interesting. Thanks. I need to have a little think about it.

@encode/django-rest-framework-core-team Anyone care to comment?

Copy link
Member

@rpkilby rpkilby left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • It would great to have a few simple tests for getattr.
  • For whatever reason, CI didn't pick up the PR? Adding tests should hopefully trigger a new build.

@yotamofek
Copy link
Author

@rpkilby - hey, I added two simple tests. Do you think it's enough?

As for the CI, Travis seems to not like my branch, maybe one of the admins can manually trigger a build?
image

@xordoquy
Copy link
Collaborator

Somehow travis doesn't seem to know about this PR so I can't trigger a manual build.

@yotamofek
Copy link
Author

@xordoquy I found it under the "Requests" tab, not under the "Pull Requests" tab.

@xordoquy
Copy link
Collaborator

Yup, but still can't do any action on it.

@yotamofek
Copy link
Author

I'll email Travis support, a quick Google search says that's what's needed in these cases.

except AttributeError:
six.reraise(info[0], info[1], info[2].tb_next)
inner_info = sys.exc_info()
six.reraise(inner_info[0], inner_info[1], outer_info[2].tb_next)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is actually necessary. It was in the original implementation, since we were re-raising from the attribute access on the underlying WSGIRequest object. In this case, we're raising from Request.__getattribute__, so catching and reraising should be superfluous.

wsgi_request = factory.get('/')

sentinel = object()
wsgi_request.__dict__['inner_property'] = sentinel
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It shouldn't be necessary to do reference the underlying `dict. Regular attribute setting should be sufficient.

wsgi_request.inner_property = sentinel

@rpkilby
Copy link
Member

rpkilby commented Nov 22, 2017

Hi @yotamofek - I've left a few comments here, but have implemented them in #5617. I'm going to go ahead and close this in favor of the updated PR. Again, thanks for submitting this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants