tornado: Replace dataclasses.asdict() call, as it is slow.

This code is called in the hot path when Tornado is processing events.
As such, making this code performant is important.  Profiling shows
that a significant portion of the time is spent calling asdict() to
serialize the UserMessageNotificationsData dataclass.  In this case
`asdict` does several steps which we do not need, such as attempting
to recurse into its fields, and deepcopy'ing the values of the fields.

In our use case, these add a notable amount of overhead:
```py3
from zerver.tornado.event_queue import UserMessageNotificationsData
from dataclasses import asdict
from timeit import timeit
o = UserMessageNotificationsData(1, False, False, False, False, False, False, False, False, False, False, False)
%timeit asdict(o)
%timeit {**vars(o)}
```

Replace the `asdict` call with a direct access of the fields.  We
perform a shallow copy because we do need to modify the resulting
fields.
This commit is contained in:
Alex Vandiver 2023-02-17 19:27:57 +00:00 committed by Tim Abbott
parent ed069ebe0e
commit 6427d85cf6
1 changed files with 5 additions and 2 deletions

View File

@ -9,7 +9,6 @@ import traceback
import uuid
from collections import deque
from contextlib import suppress
from dataclasses import asdict
from functools import lru_cache
from typing import (
AbstractSet,
@ -987,7 +986,11 @@ def process_message_event(
all_bot_user_ids=all_bot_user_ids,
)
internal_data = asdict(user_notifications_data)
# Calling asdict would be slow, as it does a deep copy; pull
# the attributes out directly and perform a shallow copy, as
# we do intend to adjust the dict.
internal_data = {**vars(user_notifications_data)}
# Remove fields sent through other pipes to save some space.
internal_data.pop("user_id")
internal_data["mentioned_user_group_id"] = mentioned_user_group_id