#37126: Make Task and TaskResult comparable
--------------------------------+--------------------------------------
     Reporter:  Johannes Maron  |                    Owner:  (none)
         Type:  New feature     |                   Status:  new
    Component:  Tasks           |                  Version:  dev
     Severity:  Normal          |               Resolution:
     Keywords:                  |             Triage Stage:  Unreviewed
    Has patch:  0               |      Needs documentation:  0
  Needs tests:  0               |  Patch needs improvement:  0
Easy pickings:  1               |                    UI/UX:  0
--------------------------------+--------------------------------------
Comment (by Johannes Maron):

 Missing benchmark sources for my previous comment:

 {{{
 import timeit
 from dataclasses import dataclass, field
 from datetime import datetime
 from typing import Any

 from django.utils.json import normalize_json
 from django.tasks.base import Task, TaskResult, TaskResultStatus

 # --- Real Task instance ---

 def my_func():
     pass

 real_task = Task.__new__(Task)
 object.__setattr__(real_task, "func", my_func)
 object.__setattr__(real_task, "priority", 0)
 object.__setattr__(real_task, "backend", "default")
 object.__setattr__(real_task, "queue_name", "default")
 object.__setattr__(real_task, "run_after", None)
 object.__setattr__(real_task, "takes_context", False)

 # --- Shared kwargs ---

 now = datetime.now()

 common_kwargs = dict(
     task=real_task,
     id="abc123",
     status=TaskResultStatus.SUCCESSFUL,
     enqueued_at=now,
     started_at=now,
     finished_at=now,
     last_attempted_at=now,
     args=[],
     kwargs={},
     backend="default",
     errors=[],
     worker_ids=["worker-1"],
 )

 # --- id-only equality variant ---

 @dataclass(frozen=True, slots=True, kw_only=True)
 class TaskResultIdEq:
     task: Any = field(compare=False)
     id: str
     status: Any = field(compare=False)
     enqueued_at: datetime | None = field(compare=False)
     started_at: datetime | None = field(compare=False)
     finished_at: datetime | None = field(compare=False)
     last_attempted_at: datetime | None = field(compare=False)
     args: list[Any] = field(compare=False)
     kwargs: dict[str, Any] = field(compare=False)
     backend: str = field(compare=False)
     errors: list = field(compare=False)
     worker_ids: list[str] = field(compare=False)
     _return_value: Any | None = field(init=False, default=None,
 compare=False)

     def __post_init__(self):
         object.__setattr__(self, "args", normalize_json(self.args))
         object.__setattr__(self, "kwargs", normalize_json(self.kwargs))

 # --- Instances to compare ---

 a_full = TaskResult(**common_kwargs)
 b_full = TaskResult(**common_kwargs)
 # equal
 c_full = TaskResult(**{**common_kwargs, "id": "other"})                  #
 not equal

 a_id = TaskResultIdEq(**common_kwargs)
 b_id = TaskResultIdEq(**common_kwargs)
 # equal
 c_id = TaskResultIdEq(**{**common_kwargs, "id": "other"})                #
 not equal

 N = 100_000_000

 results = {
     "Original == (equal)":     timeit.timeit(lambda: a_full == b_full,
 number=N),
     "Original == (not equal)": timeit.timeit(lambda: a_full == c_full,
 number=N),
     "Id-only == (equal)":      timeit.timeit(lambda: a_id == b_id,
 number=N),
     "Id-only == (not equal)":  timeit.timeit(lambda: a_id == c_id,
 number=N),
 }

 for label, t in results.items():
     print(f"{label:<30}  {t:.3f}s  ({t/N*1e9:.1f} ns/call)")
 }}}
-- 
Ticket URL: <https://code.djangoproject.com/ticket/37126#comment:2>
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 visit 
https://groups.google.com/d/msgid/django-updates/0107019e6fe32246-7143bf1c-d252-422c-9ed5-a7d5cb12bd7e-000000%40eu-central-1.amazonses.com.

Reply via email to