#36520: Performance Regression in parse_header_params -----------------------------+----------------------------------------- Reporter: David Smith | Type: Uncategorized Status: new | Component: HTTP handling Version: 5.2 | 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 -----------------------------+----------------------------------------- https://github.com/django/django/pull/18424 / #35440 simplified the `parse_header_params()` function.
This introduced a performance regression than can be seen on django-asv. [https://django.github.io/django-asv/regressions.xml link] shows 5 performance regressions on or arround 28 March 2025, all of which relate to this commit. A minimal reproduction shows a 5x performance regression. Before: {{{ In [2]: %timeit parse_header_parameters("text/plain") 500 ns ± 1.42 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each) }}} After {{{ In [2]: %timeit parse_header_parameters("text/plain") 2.65 μs ± 44.7 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each) }}} Running a [https://pypi.org/project/line-profiler/#quick-start-modern line-profile] shows: {{{ Line # Hits Time Per Hit % Time Line Contents ============================================================== 320 @line_profiler.profile 321 def parse_header_parameters(line, max_length=MAX_HEADER_LENGTH): 322 """ 323 Parse a Content-type like header. 324 Return the main content-type and a dictionary of options. 325 326 If `line` is longer than `max_length`, `ValueError` is raised. 327 """ 328 1 11.0 11.0 2.4 if max_length is not None and line and len(line) > max_length: 329 raise ValueError("Unable to parse header parameters (value too long).") 330 331 1 47.0 47.0 10.3 m = Message() 332 1 51.0 51.0 11.2 m["content-type"] = line 333 1 332.0 332.0 73.0 params = m.get_params() 334 335 1 2.0 2.0 0.4 pdict = {} 336 1 7.0 7.0 1.5 key = params.pop(0)[0].lower() 337 1 2.0 2.0 0.4 for name, value in params: 338 if not name: 339 continue 340 if isinstance(value, tuple): 341 value = collapse_rfc2231_value(value) 342 pdict[name] = value 343 1 3.0 3.0 0.7 return key, pdict }}} As I think this function is called with every request, I thought it worth raising. -- Ticket URL: <https://code.djangoproject.com/ticket/36520> 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 django-updates+unsubscr...@googlegroups.com. To view this discussion visit https://groups.google.com/d/msgid/django-updates/01070198345276d8-02273378-aaca-4507-99d2-de930e447b66-000000%40eu-central-1.amazonses.com.