#32782: Optimize _get_user_permissions by using set comprehensions
-------------------------------------+-------------------------------------
     Reporter:  Abhyudai             |                    Owner:  nobody
         Type:                       |                   Status:  closed
  Cleanup/optimization               |
    Component:  Uncategorized        |                  Version:  3.2
     Severity:  Normal               |               Resolution:  needsinfo
     Keywords:  permissions, auth    |             Triage Stage:
                                     |  Unreviewed
    Has patch:  0                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  0
Easy pickings:  1                    |                    UI/UX:  0
-------------------------------------+-------------------------------------

Comment (by Abhyudai):

 I also didn't notice any speed up even without the `:=` walrus operator
 and `f-strings`(using my original patch). My results were pretty similar
 to the ones observed by Nick.

 Although, the non-scientific benchmarking was encouraging (using `time`
 command), the more scientific one wasn't.

 For what it is worth, the script user for benchmarking was

 {{{#!python
 import os

 from django.conf.global_settings import INSTALLED_APPS
 import django
 from django.conf import settings
 from django.core.management import call_command

 import pyperf

 settings.configure(
     INSTALLED_APPS= (
         'django.contrib.auth',
         'django.contrib.contenttypes',
     ),
     DATABASES = {
         'default': {
             'ENGINE': 'django.db.backends.sqlite3',
             'NAME': os.path.join(
 os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
                 'db.sqlite3'
             ),
         }
     },
 )
 django.setup()
 call_command('migrate', verbosity=0)

 from django.contrib.auth.models import User, _user_get_permissions
 user, _ = User.objects.get_or_create(username='a', password='a')

 def test(loops):
     t0 = pyperf.perf_counter()

     # repeat to reduce impact of for loop
     for loop in range(loops):
         _user_get_permissions(user, None, 'all')
         _user_get_permissions(user, None, 'all')
         _user_get_permissions(user, None, 'all')
         _user_get_permissions(user, None, 'all')
         _user_get_permissions(user, None, 'all')
         _user_get_permissions(user, None, 'all')
         _user_get_permissions(user, None, 'all')
         _user_get_permissions(user, None, 'all')
         _user_get_permissions(user, None, 'all')
         _user_get_permissions(user, None, 'all')
         _user_get_permissions(user, None, 'all')

     return pyperf.perf_counter() - t0

 runner = pyperf.Runner()
 runner.bench_time_func('User permissions', test)

 }}}


 {{{
 Before: Mean +- std dev: 220 us +- 11 us
 After: User permissions: Mean +- std dev: 223 us +- 11 us
 }}}


 This appeared a lit weird to me because comprehensions tend to be
 computationally faster than the traditional `for` loops. At least, that is
 how they are marketed, and were sold to me :-p

 The script used for profiling was,(this was saved as `profiler.py`)
 {{{#!python
 import os

 from django.conf.global_settings import INSTALLED_APPS
 import django
 from django.conf import settings
 from django.core.management import call_command

 settings.configure(
     INSTALLED_APPS= (
         'django.contrib.auth',
         'django.contrib.contenttypes',
     ),
     DATABASES = {
         'default': {
             'ENGINE': 'django.db.backends.sqlite3',
             'NAME': os.path.join(
 os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
                 'db.sqlite3'
             ),
         }
     },
 )
 django.setup()

 from django.contrib.auth.models import User, _user_get_permissions
 user, _ = User.objects.get_or_create(username='a', password='a')

 def main():
     user.get_all_permissions()

 if __name__ == '__main__':
     main()

 }}}

 I saw a tiny increase in the percentage of time spent in the
 `_user_get_permissions` function. The earlier one took `1.29%`, while the
 newer one spent `1.31%`, although pretty insignificant but the traditional
 `for` loops one spends lesser time !

 I can't seem to find a way to attach the `pstats` files here.

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

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/068.08016f21635a31096dd3ad99daa50bec%40djangoproject.com.

Reply via email to