﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
32945	Improve performance of HttpRequest._current_scheme_host()	David Smith	nobody	"`_current_scheme_host()` currently uses `.format`. I propose that we change this to an `f-string` for a c.7.5% performance gain.

There's a few different ways this could be written, I think OptionTwo would be the one which would meet Django's f-string guidelines. I've shown a few different versions to show that moving to f-string is the big win here and adding a few extra variables (or not) as no impact. 

One thing to note is that this function is decorated with `cached_property` but I've removed this to benchmark the underlying function.


{{{
.....................
Current: Mean +- std dev: 243 us +- 4 us
.....................
Option One: Mean +- std dev: 226 us +- 2 us
.....................
Option Two: Mean +- std dev: 225 us +- 3 us
.....................
Option Three: Mean +- std dev: 226 us +- 2 us
}}}

{{{
import pyperf
from django.conf import settings
from django.http import HttpRequest
import django


settings.configure(ALLOWED_HOSTS = ['localhost'])
django.setup()

class CurrentHttpRequest(HttpRequest):
    def _current_scheme_host(self):
        return '{}://{}'.format(self.scheme, self.get_host())

class OptionOneHttpRequest(HttpRequest):
    def _current_scheme_host(self):
        return f'{self.scheme}://{self.get_host()}'

class OptionTwoHttpRequest(HttpRequest):
    def _current_scheme_host(self):
        host = self.get_host()
        return f'{self.scheme}://{host}'

class OptionThreeHttpRequest(HttpRequest):
    def _current_scheme_host(self):
        scheme = self.scheme
        host = self.get_host()
        return f'{scheme}://{host}'

def current(loops):
    request = CurrentHttpRequest()
    request.META['SERVER_NAME'] = 'localhost'
    request.META['SERVER_PORT'] = '80'
    range_it = range(loops)
    t0 = pyperf.perf_counter()

    for loop in range_it:
        request._current_scheme_host()
        request._current_scheme_host()
        request._current_scheme_host()
        request._current_scheme_host()
        request._current_scheme_host()
        request._current_scheme_host()
        request._current_scheme_host()
        request._current_scheme_host()
        request._current_scheme_host()
        request._current_scheme_host()

    return pyperf.perf_counter() - t0

def option_one(loops):
    request = OptionOneHttpRequest()
    request.META['SERVER_NAME'] = 'localhost'
    request.META['SERVER_PORT'] = '80'
    range_it = range(loops)
    t0 = pyperf.perf_counter()

    for loop in range_it:
        request._current_scheme_host()
        request._current_scheme_host()
        request._current_scheme_host()
        request._current_scheme_host()
        request._current_scheme_host()
        request._current_scheme_host()
        request._current_scheme_host()
        request._current_scheme_host()
        request._current_scheme_host()
        request._current_scheme_host()

    return pyperf.perf_counter() - t0

def option_two(loops):
    request = OptionTwoHttpRequest()
    request.META['SERVER_NAME'] = 'localhost'
    request.META['SERVER_PORT'] = '80'
    range_it = range(loops)
    t0 = pyperf.perf_counter()

    for loop in range_it:
        request._current_scheme_host()
        request._current_scheme_host()
        request._current_scheme_host()
        request._current_scheme_host()
        request._current_scheme_host()
        request._current_scheme_host()
        request._current_scheme_host()
        request._current_scheme_host()
        request._current_scheme_host()
        request._current_scheme_host()

    return pyperf.perf_counter() - t0

def option_three(loops):
    request = OptionThreeHttpRequest()
    request.META['SERVER_NAME'] = 'localhost'
    request.META['SERVER_PORT'] = '80'
    range_it = range(loops)
    t0 = pyperf.perf_counter()

    for loop in range_it:
        request._current_scheme_host()
        request._current_scheme_host()
        request._current_scheme_host()
        request._current_scheme_host()
        request._current_scheme_host()
        request._current_scheme_host()
        request._current_scheme_host()
        request._current_scheme_host()
        request._current_scheme_host()
        request._current_scheme_host()

    return pyperf.perf_counter() - t0

runner = pyperf.Runner()
runner.bench_time_func('Current', current)
runner.bench_time_func('Option One', option_one)
runner.bench_time_func('Option Two', option_two)
runner.bench_time_func('Option Three', option_three)

}}}"	Cleanup/optimization	closed	HTTP handling	3.2	Normal	invalid			Unreviewed	0	0	0	0	0	0
