From 27216892547bb073777056379d549a6dc42872cb Mon Sep 17 00:00:00 2001 From: Rapptz Date: Mon, 24 Sep 2018 23:22:49 -0400 Subject: [PATCH] Optimise tight loops in DiscordGateway.received_message * type(x) is y is faster than isinstance(x, y) * Re-arrange if-statements for common statements * Drop handler getattr for most events that don't use it --- discord/client.py | 13 ++++----- discord/gateway.py | 68 +++++++++++++++++++++++----------------------- discord/shard.py | 3 +- discord/state.py | 13 ++++++++- 4 files changed, 53 insertions(+), 44 deletions(-) diff --git a/discord/client.py b/discord/client.py index 31b2a5a1d..23907574b 100644 --- a/discord/client.py +++ b/discord/client.py @@ -125,7 +125,11 @@ class Client: proxy_auth = options.pop('proxy_auth', None) self.http = HTTPClient(connector, proxy=proxy, proxy_auth=proxy_auth, loop=self.loop) - self._connection = ConnectionState(dispatch=self.dispatch, chunker=self._chunker, + self._handlers = { + 'ready': self._handle_ready + } + + self._connection = ConnectionState(dispatch=self.dispatch, chunker=self._chunker, handlers=self._handlers, syncer=self._syncer, http=self.http, loop=self.loop, **options) self._connection.shard_count = self.shard_count @@ -261,13 +265,6 @@ class Client: for idx in reversed(removed): del listeners[idx] - try: - actual_handler = getattr(self, handler) - except AttributeError: - pass - else: - actual_handler(*args, **kwargs) - try: coro = getattr(self, method) except AttributeError: diff --git a/discord/gateway.py b/discord/gateway.py index 66b041864..23b5de77b 100644 --- a/discord/gateway.py +++ b/discord/gateway.py @@ -312,7 +312,7 @@ class DiscordWebSocket(websockets.client.WebSocketClientProtocol): async def received_message(self, msg): self._dispatch('socket_raw_receive', msg) - if isinstance(msg, bytes): + if type(msg) is bytes: self._buffer.extend(msg) if len(msg) >= 4: @@ -336,44 +336,44 @@ class DiscordWebSocket(websockets.client.WebSocketClientProtocol): if seq is not None: self.sequence = seq - if op == self.RECONNECT: - # "reconnect" can only be handled by the Client - # so we terminate our connection and raise an - # internal exception signalling to reconnect. - log.info('Received RECONNECT opcode.') - await self.close() - raise ResumeWebSocket(self.shard_id) + if op != self.DISPATCH: + if op == self.RECONNECT: + # "reconnect" can only be handled by the Client + # so we terminate our connection and raise an + # internal exception signalling to reconnect. + log.info('Received RECONNECT opcode.') + await self.close() + raise ResumeWebSocket(self.shard_id) - if op == self.HEARTBEAT_ACK: - self._keep_alive.ack() - return + if op == self.HEARTBEAT_ACK: + self._keep_alive.ack() + return - if op == self.HEARTBEAT: - beat = self._keep_alive.get_payload() - await self.send_as_json(beat) - return + if op == self.HEARTBEAT: + beat = self._keep_alive.get_payload() + await self.send_as_json(beat) + return - if op == self.HELLO: - interval = data['heartbeat_interval'] / 1000.0 - self._keep_alive = KeepAliveHandler(ws=self, interval=interval, shard_id=self.shard_id) - # send a heartbeat immediately - await self.send_as_json(self._keep_alive.get_payload()) - self._keep_alive.start() - return + if op == self.HELLO: + interval = data['heartbeat_interval'] / 1000.0 + self._keep_alive = KeepAliveHandler(ws=self, interval=interval, shard_id=self.shard_id) + # send a heartbeat immediately + await self.send_as_json(self._keep_alive.get_payload()) + self._keep_alive.start() + return - if op == self.INVALIDATE_SESSION: - if data == True: - await asyncio.sleep(5.0, loop=self.loop) - await self.close() - raise ResumeWebSocket(self.shard_id) + if op == self.INVALIDATE_SESSION: + if data == True: + await asyncio.sleep(5.0, loop=self.loop) + await self.close() + raise ResumeWebSocket(self.shard_id) - self.sequence = None - self.session_id = None - log.info('Shard ID %s session has been invalidated.' % self.shard_id) - await self.identify() - return + self.sequence = None + self.session_id = None + log.info('Shard ID %s session has been invalidated.' % self.shard_id) + await self.identify() + return - if op != self.DISPATCH: log.warning('Unknown OP code %s.', op) return @@ -386,7 +386,7 @@ class DiscordWebSocket(websockets.client.WebSocketClientProtocol): log.info('Shard ID %s has connected to Gateway: %s (Session ID: %s).', self.shard_id, ', '.join(trace), self.session_id) - if event == 'RESUMED': + elif event == 'RESUMED': self._trace = trace = data.get('_trace', []) log.info('Shard ID %s has successfully RESUMED session %s under trace %s.', self.shard_id, self.session_id, ', '.join(trace)) diff --git a/discord/shard.py b/discord/shard.py index 55600e560..d0da4151d 100644 --- a/discord/shard.py +++ b/discord/shard.py @@ -124,7 +124,8 @@ class AutoShardedClient(Client): raise ClientException('shard_ids parameter must be a list or a tuple.') self._connection = AutoShardedConnectionState(dispatch=self.dispatch, chunker=self._chunker, - syncer=self._syncer, http=self.http, loop=self.loop, **kwargs) + handlers=self._handlers, syncer=self._syncer, + http=self.http, loop=self.loop, **kwargs) # instead of a single websocket, we have multiple # the key is the shard_id diff --git a/discord/state.py b/discord/state.py index 676ca513b..53e453f34 100644 --- a/discord/state.py +++ b/discord/state.py @@ -54,7 +54,7 @@ log = logging.getLogger(__name__) ReadyState = namedtuple('ReadyState', ('launch', 'guilds')) class ConnectionState: - def __init__(self, *, dispatch, chunker, syncer, http, loop, **options): + def __init__(self, *, dispatch, chunker, handlers, syncer, http, loop, **options): self.loop = loop self.http = http self.max_messages = max(options.get('max_messages', 5000), 100) @@ -62,6 +62,7 @@ class ConnectionState: self.chunker = chunker self.syncer = syncer self.is_bot = None + self.handlers = handlers self.shard_count = None self._ready_task = None self._fetch_offline = options.get('fetch_offline_members', True) @@ -127,6 +128,14 @@ class ConnectionState: for index in reversed(removed): del self._listeners[index] + def call_handlers(self, key, *args, **kwargs): + try: + func = self.handlers[key] + except KeyError: + pass + else: + func(*args, **kwargs) + @property def self_id(self): u = self.user @@ -308,6 +317,7 @@ class ConnectionState: pass else: # dispatch the event + self.call_handlers('ready') self.dispatch('ready') finally: self._ready_task = None @@ -960,6 +970,7 @@ class AutoShardedConnectionState(ConnectionState): self._ready_task = None # dispatch the event + self.call_handlers('ready') self.dispatch('ready') def parse_ready(self, data):