Cache url_for calls with lru_cache

This commit adds a caching_url_for using functools.lru_cache (currently
with maxsize at 4096 entries) and replaces flask.url_for with it, as
there is no harm in doing so.

This greatly improves template generation speed, from ~115ms to ~75ms on
the front page (using the simple benchmark introduced in the previous
commit).
This commit is contained in:
TheAMM 2019-04-08 19:37:01 +03:00
parent b0c51e9fa0
commit 7b6cf64763
2 changed files with 33 additions and 0 deletions

View File

@ -8,9 +8,15 @@ from flask_assets import Bundle # noqa F401
from nyaa.api_handler import api_blueprint
from nyaa.extensions import assets, cache, db, fix_paginate, toolbar
from nyaa.template_utils import bp as template_utils_bp
from nyaa.template_utils import caching_url_for
from nyaa.utils import random_string
from nyaa.views import register_views
# Replace the Flask url_for with our cached version, since there's no real harm in doing so
# (caching_url_for has stored a reference to the OG url_for, so we won't recurse)
# Touching globals like this is a bit dirty, but nicer than replacing every url_for usage
flask.url_for = caching_url_for
def create_app(config):
""" Nyaa app factory """
@ -86,6 +92,10 @@ def create_app(config):
app.jinja_env.lstrip_blocks = True
app.jinja_env.trim_blocks = True
# The default jinja_env has the OG Flask url_for (from before we replaced it),
# so update the globals with our version
app.jinja_env.globals['url_for'] = flask.url_for
# Database
fix_paginate() # This has to be before the database is initialized
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

View File

@ -1,3 +1,4 @@
import functools
import os.path
import re
from datetime import datetime
@ -25,6 +26,28 @@ def create_magnet_from_es_torrent():
# ######################### TEMPLATE GLOBALS #########################
flask_url_for = flask.url_for
@functools.lru_cache(maxsize=1024*4)
def _caching_url_for(endpoint, **values):
return flask_url_for(endpoint, **values)
@bp.app_template_global()
def caching_url_for(*args, **kwargs):
try:
# lru_cache requires the arguments to be hashable.
# Majority of the time, they are! But there are some small edge-cases,
# like our copypasted pagination, parameters can be lists.
# Attempt caching first:
return _caching_url_for(*args, **kwargs)
except TypeError:
# Then fall back to the original url_for.
# We could convert the lists to tuples, but the savings are marginal.
return flask_url_for(*args, **kwargs)
@bp.app_template_global()
def static_cachebuster(filename):
""" Adds a ?t=<mtime> cachebuster to the given path, if the file exists.