[Django] #30498: lazy() class preparation is not being cached correctly

7 views
Skip to first unread message

Django

unread,
May 22, 2019, 5:07:11 AM5/22/19
to django-...@googlegroups.com
#30498: lazy() class preparation is not being cached correctly
------------------------------------------------+------------------------
Reporter: Ran Benita | Owner: nobody
Type: Cleanup/optimization | Status: new
Component: Utilities | Version: master
Severity: Normal | Keywords:
Triage Stage: Unreviewed | Has patch: 0
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
------------------------------------------------+------------------------
Doing `self.__prepared = True` changes the instance, but the intention is
to change the class variable:
https://github.com/django/django/blob/888fdf182e164fa4b24aa82fa833c90a2b9bee7a/django/utils/functional.py#L82

This makes functions like gettext_lazy, format_lazy and reverse_lazy a lot
slower than they ought to be.

Regressed in Django 1.8 (b4e76f30d12bfa8a53cc297c60055c6f4629cc4c).

Using this micro-benchmark on Python 3.7:

{{{#!python
import cProfile
from django.utils.functional import lazy

def identity(x): return x
lazy_identity = lazy(identity, int)
cProfile.run("for i in range(10000): str(lazy_identity(1))")
}}}


Before:

{{{
910049 function calls in 0.208 seconds

Ordered by: standard name

ncalls tottime percall cumtime percall filename:lineno(function)
1 0.010 0.010 0.208 0.208 <string>:1(<module>)
10000 0.001 0.000 0.001 0.000 bench.py:4(identity)
10000 0.005 0.000 0.010 0.000 functional.py:105(__str__)
10000 0.004 0.000 0.188 0.000
functional.py:159(__wrapper__)
10000 0.007 0.000 0.185 0.000 functional.py:76(__init__)
10000 0.089 0.000 0.178 0.000
functional.py:83(__prepare_class__)
10000 0.004 0.000 0.005 0.000 functional.py:99(__cast)
1 0.000 0.000 0.208 0.208 {built-in method
builtins.exec}
840000 0.087 0.000 0.087 0.000 {built-in method
builtins.hasattr}
46 0.000 0.000 0.000 0.000 {built-in method
builtins.setattr}
1 0.000 0.000 0.000 0.000 {method 'disable' of
'_lsprof.Profiler' objects}
10000 0.002 0.000 0.002 0.000 {method 'mro' of 'type'
objects}
}}}

After:

{{{
50135 function calls in 0.025 seconds

Ordered by: standard name

ncalls tottime percall cumtime percall filename:lineno(function)
1 0.008 0.008 0.025 0.025 <string>:1(<module>)
10000 0.001 0.000 0.001 0.000 bench.py:4(identity)
10000 0.005 0.000 0.009 0.000 functional.py:105(__str__)
10000 0.003 0.000 0.008 0.000
functional.py:159(__wrapper__)
10000 0.005 0.000 0.005 0.000 functional.py:76(__init__)
1 0.000 0.000 0.000 0.000
functional.py:83(__prepare_class__)
10000 0.004 0.000 0.005 0.000 functional.py:99(__cast)
1 0.000 0.000 0.025 0.025 {built-in method
builtins.exec}
84 0.000 0.000 0.000 0.000 {built-in method
builtins.hasattr}
46 0.000 0.000 0.000 0.000 {built-in method
builtins.setattr}
1 0.000 0.000 0.000 0.000 {method 'disable' of
'_lsprof.Profiler' objects}
1 0.000 0.000 0.000 0.000 {method 'mro' of 'type'
objects}
}}}

--
Ticket URL: <https://code.djangoproject.com/ticket/30498>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
May 22, 2019, 5:12:44 AM5/22/19
to django-...@googlegroups.com
#30498: lazy() class preparation is not being cached correctly
-------------------------------------+-------------------------------------

Reporter: Ran Benita | Owner: nobody
Type: | Status: new
Cleanup/optimization |
Component: Utilities | Version: master
Severity: Normal | Resolution:
Keywords: | Triage Stage:
| Unreviewed
Has patch: 1 | Needs documentation: 0

Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Ran Benita):

* has_patch: 0 => 1


Comment:

PR: https://github.com/django/django/pull/11399

--
Ticket URL: <https://code.djangoproject.com/ticket/30498#comment:1>

Django

unread,
May 22, 2019, 6:30:22 AM5/22/19
to django-...@googlegroups.com
#30498: lazy() class preparation is not being cached correctly.
-------------------------------------+-------------------------------------
Reporter: Ran Benita | Owner: Ran
Type: | Benita
Cleanup/optimization | Status: assigned
Component: Utilities | Version: master
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0

Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by felixxm):

* owner: nobody => Ran Benita
* status: new => assigned
* stage: Unreviewed => Accepted


Comment:

Thanks for the report! Reproduced at
888fdf182e164fa4b24aa82fa833c90a2b9bee7a.

--
Ticket URL: <https://code.djangoproject.com/ticket/30498#comment:2>

Django

unread,
May 22, 2019, 4:18:25 PM5/22/19
to django-...@googlegroups.com
#30498: lazy() class preparation is not being cached correctly.
-------------------------------------+-------------------------------------
Reporter: Ran Benita | Owner: Ran
Type: | Benita
Cleanup/optimization | Status: closed
Component: Utilities | Version: master
Severity: Normal | Resolution: fixed
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0

Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Mariusz Felisiak <felisiak.mariusz@…>):

* status: assigned => closed
* resolution: => fixed


Comment:

In [changeset:"a2c31e12da272acc76f3a3a0157fae9a7f6477ac" a2c31e12]:
{{{
#!CommitTicketReference repository=""
revision="a2c31e12da272acc76f3a3a0157fae9a7f6477ac"
Fixed #30498 -- Fixed proxy class caching in lazy().

lazy() should prepare the proxy class only once (the first time it's
used) not on every call.

Regression in b4e76f30d12bfa8a53cc297c60055c6f4629cc4c.
}}}

--
Ticket URL: <https://code.djangoproject.com/ticket/30498#comment:3>

Reply all
Reply to author
Forward
0 new messages