Skip to content
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

Django nodes cache #40

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open

Django nodes cache #40

wants to merge 7 commits into from

Conversation

iurisilvio
Copy link

@iurisilvio iurisilvio commented Apr 9, 2022

It is really slow to parse templates everytime you call render_block and it is a static information, so you can cache it in memory.

I did some benchmarking here and this node cache improved performance ~20%.

Most part of the work was done by @walison17, I just wrote a test and did the benckmark.

@iurisilvio iurisilvio requested a review from clokep as a code owner April 9, 2022 10:31
Copy link
Owner

@clokep clokep left a comment

Choose a reason for hiding this comment

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

Thanks for the contribution! Seems like it would be a nice improvement.

render_block/django.py Outdated Show resolved Hide resolved
Co-authored-by: Patrick Cloke <clokep@users.noreply.github.com>
@clokep clokep self-requested a review April 11, 2022 16:18
@clokep
Copy link
Owner

clokep commented Apr 11, 2022

Looks like this needs black run against it for formatting! 👍

@iurisilvio
Copy link
Author

Yes, I ran black and fixed the formatting.

Copy link
Owner

@clokep clokep left a comment

Choose a reason for hiding this comment

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

I think this looks OK, but the logic is a bit confusing. I need to dig a bit into some edge cases and see if it can cause any problems.

@@ -99,7 +119,7 @@ def _render_template_block_nodelist(nodelist, block_name, context):

# If the name matches, you're all set and we found the block!
if node.name == block_name:
return node.render(context)
return node, context.render_context
Copy link
Owner

Choose a reason for hiding this comment

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

I'm having some trouble wrapping my brain around some of this change, it seems like _find_template_block_nodelist really only cares about the render_context after this change and not the context itself.

(This is also true of _find_template_block.)

Copy link
Author

Choose a reason for hiding this comment

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

The Context/RequestContext has the data to be rendered. The context.render_context has only the template structure that can be reused, so I always need a new Context, but can reuse the render context.

return _render_template_block(template, block_name, context_instance)
except BlockNotFound:
# The block wasn't found in the current template.
node, render_context = _NODES_CACHE[cache_key]
Copy link
Owner

Choose a reason for hiding this comment

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

I'm slightly worried that a global cache might not be safe to use here, but it likely is OK in almost every case.

Copy link
Author

Choose a reason for hiding this comment

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

I agree. Django has a cache per instance of template cached loader. https://github.com/django/django/blob/21d8ea4eb3e22d458515b5278c8cd3a15b069799/django/template/loaders/cached.py#L16

Django template loaders have to handle multiple loader instances and do things like template overriding, that are impossible with a global cache.

This lib is a lot simpler than Django template loaders, so the global cache would work fine.

if not template.engine.debug:
_NODES_CACHE[cache_key] = node, render_context

context_instance.render_context = render_context
Copy link
Owner

Choose a reason for hiding this comment

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

There's a comment added in #25 that implies reusing render contexts might be unsafe. That does have a test though so hopefully it is OK.

Copy link
Author

Choose a reason for hiding this comment

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

I think it is ok.

The issue #25 fixed Context object reuse, but we're just reusing the render_context inside a new Context. https://github.com/django/django/blob/main/django/template/loaders/cached.py#L72

@clokep clokep self-requested a review May 9, 2022 13:29
@iurisilvio
Copy link
Author

I added a commit here to support anonymous templates. It is a case where template.name is None, so it was clashing cache keys.

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

Successfully merging this pull request may close these issues.

2 participants