From 43fb0ddf980d79885b3dfad0abb48e51c8f84e68 Mon Sep 17 00:00:00 2001 From: Andrew Schultz Date: Sun, 22 Sep 2024 08:01:06 -0600 Subject: [PATCH 1/3] Speed up read_next_message - Pre-allocate message_bytes to avoid resizing. - Use bitwise AND (& 3) instead of modulus (% 4) The larger the payload, the more the speedup. In bytes: - 1: -3% - 2: +8% - 4: +11% - 8: +18% - 16: +25% - 32: +28% - 128: +29% - 512: +31% - 1Ki: +33% - 4Ki: +34% - 8Ki: +33% - 16Ki:+33% --- websocket_server/websocket_server.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/websocket_server/websocket_server.py b/websocket_server/websocket_server.py index 083ee17..4ca7ed9 100644 --- a/websocket_server/websocket_server.py +++ b/websocket_server/websocket_server.py @@ -334,10 +334,11 @@ def read_next_message(self): payload_length = struct.unpack(">Q", self.rfile.read(8))[0] masks = self.read_bytes(4) - message_bytes = bytearray() - for message_byte in self.read_bytes(payload_length): - message_byte ^= masks[len(message_bytes) % 4] - message_bytes.append(message_byte) + raw_bytes = self.read_bytes(payload_length) + message_bytes = bytearray(len(raw_bytes)) + for i, message_byte in enumerate(raw_bytes): + message_byte ^= masks[i & 3] + message_bytes[i] = message_byte opcode_handler(self, message_bytes.decode('utf8')) def send_message(self, message): From bf53167496a8113673d4248cded4f56de7cbf7cc Mon Sep 17 00:00:00 2001 From: Andrew Schultz Date: Fri, 18 Oct 2024 21:06:07 -0600 Subject: [PATCH 2/3] Speed up read_next_message zip payload and cycle(masks). Slower for small payloads. But much faster for larger ones. --- websocket_server/websocket_server.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/websocket_server/websocket_server.py b/websocket_server/websocket_server.py index 4ca7ed9..a2e10dd 100644 --- a/websocket_server/websocket_server.py +++ b/websocket_server/websocket_server.py @@ -1,6 +1,7 @@ # Author: Johan Hanssen Seferidis # License: MIT +from itertools import cycle import sys import struct import ssl @@ -334,11 +335,8 @@ def read_next_message(self): payload_length = struct.unpack(">Q", self.rfile.read(8))[0] masks = self.read_bytes(4) - raw_bytes = self.read_bytes(payload_length) - message_bytes = bytearray(len(raw_bytes)) - for i, message_byte in enumerate(raw_bytes): - message_byte ^= masks[i & 3] - message_bytes[i] = message_byte + payload = self.read_bytes(payload_length) + message_bytes = bytearray([byte ^ mask for byte, mask in zip(payload, cycle(masks))]) opcode_handler(self, message_bytes.decode('utf8')) def send_message(self, message): From 6929204c2eee76666941a5974e6a6672ab02cd98 Mon Sep 17 00:00:00 2001 From: Andrew Schultz Date: Fri, 18 Oct 2024 21:11:11 -0600 Subject: [PATCH 3/3] Bump version 0.6.5 --- releases.txt | 3 +++ setup.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/releases.txt b/releases.txt index 2fda06c..1d1aaa1 100644 --- a/releases.txt +++ b/releases.txt @@ -32,3 +32,6 @@ - Add deny_new_connections & allow_new_connections - Fix disconnect_clients_gracefully to now take params - Fix shutdown_gracefully unused param + +0.6.5 +- Speed up read_next_message diff --git a/setup.py b/setup.py index 684b88d..02ab047 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ from distutils.command.install import install -VERSION = '0.6.4' +VERSION = '0.6.5' def get_tag_version():