django icon indicating copy to clipboard operation
django copied to clipboard

lift up values to last context to speed up access

Open horpto opened this issue 2 years ago • 3 comments

from django.template.context import *
from timeit import timeit

class UpContext(Context):
    def __getitem__(self, key):
        val = super().__getitem__(key)
        self.dicts[-1][key] = val
        return val

c = Context({'Q': 34})
c1 = UpContext({'Q': 34})

for i in range(10):
    c.push(d=i)
    c1.push(d=i)

def f():
    c['Q']

def f1():
    c1['Q']

>>> timeit(f)
1.316134085005615
>>> timeit(f1)
1.2122753569856286

horpto avatar Jun 09 '21 16:06 horpto

Hello @horpto! Thank you for your contribution 💪

As it's your first contribution be sure to check out the patch review checklist.

If you're fixing a ticket from Trac make sure to set the "Has patch" flag and include a link to this PR in the ticket!

If you have any design or process questions then you can ask in the Django forum.

Welcome aboard ⛵️!

github-actions[bot] avatar Jun 09 '21 16:06 github-actions[bot]

Howdy @horpto, if you want to flesh this out could you open a ticket? That's how we get eyes on things.

I'm skeptical at first glance. It looks a lot like set_upward() but without checking whether the key was there. Creates some overlapping responsibilities.

Thanks for the timing script, but on the machine I happen to be sitting at, I see a wash:

>>> timeit(f)
1.1956139059999984
>>> timeit(f1)
1.1862169209999998

jacobtylerwalls avatar Jul 05 '21 21:07 jacobtylerwalls

FWIW, instrumenting BaseContext.__getitem__ like so:

        for i, d in enumerate(reversed(self.dicts)):
            if key in d:
                print(f'found at,{i},for context length,{len(self.dicts)}')

and running the test suite will give you ... 2.5million data points, many of which will inevitably be testing the same dict/vars, but still. Extracting the depth found and context layer count into sequences of ints (found_at and context_length here):

from statistics import mean, median, mode

print(f'mean found is {mean(found_at)}')
print(f'median found is {median(found_at)}')
print(f'mode found is {mode(found_at)}')

print(f'mean context depth is {mean(ctx_length)}')
print(f'median context depth is {median(ctx_length)}')
print(f'mode context depth is {mode(ctx_length)}')

gives me:

mean found is 0.784014847054643
median found is 0
mode found is 0
mean context depth is 6.096137729352078
median context depth is 6
mode context depth is 4

Off the top of my head, I think the most expensive variables to request are the singletons True, False and None because they're always the first/bottom layer...

kezabelle avatar Jul 06 '21 12:07 kezabelle

Closing due to inactivity.

felixxm avatar Mar 17 '23 08:03 felixxm