performance improvements
Replaced server member lists, channel lists, and private channel lists with dicts. This allows O(1) lookups and removes (previously it would be an O(N) operation to lookup or remove). I did pretty extensive testing and benchmarking to compare the performance of using lists vs using dicts. Iterating through lists to find an item is only faster in the average case for extremely small lists (less than 3 items). For 100 items, using a dict is about 10 times faster on average (and about 100 times faster for 1000 items). The overhead in dicts is in memory usage and initial creation time. Creating and populating a dict is about 2 to 3 times slower than creating and appending items to a list. However this cost is still tiny. For 1000 items this equates to about a 70 microsecond difference (on an i7 CPU) for populating the entire dict. The memory overhead for a dict (compared to a list) is about 25-60 KB per 1000 items (can vary depending on dict resizing). Originally I wanted to use OrderedDicts to presereve order, but in my testing OrderedDicts have about 6x the memory overhead compared to normal dicts.
This commit is contained in:
		| @@ -89,21 +89,47 @@ class Server(Hashable): | ||||
|                   '_default_role', '_default_channel', 'roles' ] | ||||
|  | ||||
|     def __init__(self, **kwargs): | ||||
|         self.channels = [] | ||||
|         self._channels = {} | ||||
|         self.owner = None | ||||
|         self.members = [] | ||||
|         self._members = {} | ||||
|         self._from_data(kwargs) | ||||
|  | ||||
|     @property | ||||
|     def channels(self): | ||||
|         return self._channels.values() | ||||
|  | ||||
|     def get_channel(self, channel_id): | ||||
|         return self._channels.get(channel_id) | ||||
|  | ||||
|     def add_channel(self, channel): | ||||
|         self._channels[channel.id] = channel | ||||
|  | ||||
|     def remove_channel(self, channel): | ||||
|         self._channels.pop(channel.id, None) | ||||
|  | ||||
|     @property | ||||
|     def members(self): | ||||
|         return self._members.values() | ||||
|  | ||||
|     def get_member(self, user_id): | ||||
|         return self._members.get(user_id) | ||||
|  | ||||
|     def add_member(self, member): | ||||
|         self._members[member.id] = member | ||||
|  | ||||
|     def remove_member(self, member): | ||||
|         self._members.pop(member.id, None) | ||||
|  | ||||
|     def __str__(self): | ||||
|         return self.name | ||||
|  | ||||
|     def _update_voice_state(self, data): | ||||
|         user_id = data.get('user_id') | ||||
|         member = utils.find(lambda m: m.id == user_id, self.members) | ||||
|         member = self.get_member(user_id) | ||||
|         before = copy.copy(member) | ||||
|         if member is not None: | ||||
|             ch_id = data.get('channel_id') | ||||
|             channel = utils.find(lambda c: c.id == ch_id, self.channels) | ||||
|             channel = self.get_channel(ch_id) | ||||
|             member.update_voice_state(voice_channel=channel, **data) | ||||
|         return before, member | ||||
|  | ||||
| @@ -137,11 +163,11 @@ class Server(Hashable): | ||||
|             if member.id == owner_id: | ||||
|                 self.owner = member | ||||
|  | ||||
|             self.members.append(member) | ||||
|             self.add_member(member) | ||||
|  | ||||
|         for presence in guild.get('presences', []): | ||||
|             user_id = presence['user']['id'] | ||||
|             member = utils.find(lambda m: m.id == user_id, self.members) | ||||
|             member = self.get_member(user_id) | ||||
|             if member is not None: | ||||
|                 member.status = presence['status'] | ||||
|                 try: | ||||
| @@ -153,10 +179,12 @@ class Server(Hashable): | ||||
|  | ||||
|         if 'channels' in guild: | ||||
|             channels = guild['channels'] | ||||
|             self.channels = [Channel(server=self, **c) for c in channels] | ||||
|             for c in channels: | ||||
|                 channel = Channel(server=self, **c) | ||||
|                 self.add_channel(channel) | ||||
|  | ||||
|         afk_id = guild.get('afk_channel_id') | ||||
|         self.afk_channel = utils.find(lambda c: c.id == afk_id, self.channels) | ||||
|         self.afk_channel = self.get_channel(afk_id) | ||||
|  | ||||
|         for obj in guild.get('voice_states', []): | ||||
|             self._update_voice_state(obj) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user