Various speed optimizations in various places, following further profiling.

This commit is contained in:
Griatch 2012-09-20 00:47:28 +02:00
parent 83fa9397d5
commit 4c83d3e7a1
7 changed files with 75 additions and 59 deletions

View file

@ -142,7 +142,8 @@ def get_and_merge_cmdsets(caller):
# report cmdset errors to user (these should already have been logged)
yield [caller.msg(cmdset.message) for cmdset in cmdsets if cmdset.key == "_CMDSET_ERROR"]
# sort cmdsets after reverse priority (highest prio are merged in last)
cmdsets = yield sorted(cmdsets, key=lambda x: x.priority)
yield cmdsets.sort(key=lambda x: x.priority)
#cmdsets = yield sorted(cmdsets, key=lambda x: x.priority)
if cmdsets:
# Merge all command sets into one, beginning with the lowest-prio one

View file

@ -144,10 +144,12 @@ class CmdSet(object):
if key:
self.key = key
self.commands = []
self.system_commands = []
self.actual_mergetype = self.mergetype
self.cmdsetobj = cmdsetobj
# initialize system
self.at_cmdset_creation()
self._contains_cache = {}
# Priority-sensitive merge operations for cmdsets
@ -223,7 +225,13 @@ class CmdSet(object):
Returns True if this cmdset contains the given command (as defined
by command name and aliases). This allows for things like 'if cmd in cmdset'
"""
return othercmd in self.commands
# optimization test
try:
return self._contains_cache[othercmd]
except KeyError:
ret = othercmd in self.commands
self._contains_cache[othercmd] = ret
return ret
def __add__(self, cmdset_b):
"""
@ -327,18 +335,29 @@ class CmdSet(object):
cmds = [self._instantiate(c) for c in cmd]
else:
cmds = [self._instantiate(cmd)]
commands = self.commands
system_commands = self.system_commands
for cmd in cmds:
# add all commands
if not hasattr(cmd, 'obj'):
cmd.obj = self.cmdsetobj
try:
ic = self.commands.index(cmd)
self.commands[ic] = cmd # replace
ic = commands.index(cmd)
commands[ic] = cmd # replace
except ValueError:
self.commands.append(cmd)
commands.append(cmd)
# extra run to make sure to avoid doublets
self.commands = list(set(self.commands))
self.commands = list(set(commands))
#print "In cmdset.add(cmd):", self.key, cmd
# add system_command to separate list as well,
# for quick look-up
if cmd.key.startswith("__"):
try:
ic = system_commands.index(cmd)
system_commands[ic] = cmd # replace
except ValueError:
system_commands.append(cmd)
def remove(self, cmd):
"""
@ -369,7 +388,8 @@ class CmdSet(object):
commands starting with double underscore __.
These are excempt from merge operations.
"""
return [cmd for cmd in self.commands if cmd.key.startswith('__')]
return self.system_commands
#return [cmd for cmd in self.commands if cmd.key.startswith('__')]
def make_unique(self, caller):
"""

View file

@ -29,8 +29,8 @@ class CommandMeta(type):
mcs.aliases = [str(alias).strip().lower() for alias in mcs.aliases]
# optimization - a set is much faster to match against than a list
mcs._matchset = set([mcs.key] + mcs.aliases)
# optimization for retrieving aliases and key as one list
mcs._keyaliases = [mcs.key] + mcs.aliases
# optimization for looping over keys+aliases
mcs._keyaliases = tuple(mcs._matchset)
# by default we don't save the command between runs
if not hasattr(mcs, "save_for_next"):

View file

@ -44,7 +44,6 @@ _ME = _("me")
_SELF = _("self")
_HERE = _("here")
def clean_content_cache(obj):
"Clean obj's content cache"
_SA(obj, "_contents_cache", None)
@ -428,8 +427,8 @@ class ObjectDB(TypedObject):
Retrieve sessions connected to this object.
"""
# if the player is not connected, this will simply be an empty list.
if self.player:
return self.player.sessions
if _GA(self, "player"):
return _GA(_GA(self, "player"), "sessions")
return []
sessions = property(__sessions_get)
@ -439,14 +438,15 @@ class ObjectDB(TypedObject):
Convenience function for checking if an active player is
currently connected to this object
"""
return any(self.sessions)
return any(_GA(self, "sessions"))
has_player = property(__has_player_get)
is_player = property(__has_player_get)
#@property
def __is_superuser_get(self):
"Check if user has a player, and if so, if it is a superuser."
return any(self.sessions) and self.player.is_superuser
#return any(self.sessions) and self.player.is_superuser
return any(_GA(self, "sessions")) and _GA(_GA(self, "player"), "is_superuser")
is_superuser = property(__is_superuser_get)
# contents

View file

@ -637,31 +637,26 @@ class Object(TypeClass):
"""
if not pobject:
return
string = "{c%s{n" % self.name
desc = self.attr("desc")
# get and identify all objects
visible = (con for con in self.contents if con != pobject and con.access(pobject, "view"))
exits, users, things = [], [], []
for con in visible:
key = con.key
if con.destination:
exits.append(key)
elif con.has_player:
users.append("{c%s{n" % key)
else:
things.append(key)
# get description, build string
string = "{c%s{n" % self.key
desc = self.db.desc
if desc:
string += "\n %s" % desc
exits = []
users = []
things = []
for content in [con for con in self.contents if con.access(pobject, 'view')]:
if content == pobject:
continue
name = content.name
if content.destination:
exits.append(name)
elif content.has_player:
users.append(name)
else:
things.append(name)
if exits:
string += "\n{wExits:{n " + ", ".join(exits)
if users or things:
string += "\n{wYou see: {n"
if users:
string += "{c" + ", ".join(users) + "{n "
if things:
string += ", ".join(things)
string += "\n{wYou see:{n " + ", ".join(users + things)
return string
def at_desc(self, looker=None):

View file

@ -180,9 +180,9 @@ class PlayerDB(TypedObject):
"Parent must be initiated first"
TypedObject.__init__(self, *args, **kwargs)
# handlers
self.cmdset = CmdSetHandler(self)
self.cmdset.update(init_mode=True)
self.nicks = PlayerNickHandler(self)
_SA(self, "cmdset", CmdSetHandler(self))
_GA(self, "cmdset").update(init_mode=True)
_SA(self, "nicks", PlayerNickHandler(self))
# Wrapper properties to easily set database fields. These are
# @property decorators that allows to access these fields using
@ -240,21 +240,21 @@ class PlayerDB(TypedObject):
#@property
def cmdset_storage_get(self):
"Getter. Allows for value = self.name. Returns a list of cmdset_storage."
if self.db_cmdset_storage:
return [path.strip() for path in self.db_cmdset_storage.split(',')]
if _GA(self, "db_cmdset_storage"):
return [path.strip() for path in _GA(self, "db_cmdset_storage").split(',')]
return []
#@cmdset_storage.setter
def cmdset_storage_set(self, value):
"Setter. Allows for self.name = value. Stores as a comma-separated string."
if utils.is_iter(value):
value = ",".join([str(val).strip() for val in value])
self.db_cmdset_storage = value
self.save()
_SA(self, "db_cmdset_storage", value)
_GA(self, "save")()
#@cmdset_storage.deleter
def cmdset_storage_del(self):
"Deleter. Allows for del self.name"
self.db_cmdset_storage = ""
self.save()
_SA(self, "db_cmdset_storage", "")
_GA(self, "save")()
cmdset_storage = property(cmdset_storage_get, cmdset_storage_set, cmdset_storage_del)
#@property
@ -281,10 +281,10 @@ class PlayerDB(TypedObject):
#
def __str__(self):
return smart_str("%s(player %s)" % (self.name, self.dbid))
return smart_str("%s(player %s)" % (_GA(self, "name"), _GA(self, "dbid")))
def __unicode__(self):
return u"%s(player#%s)" % (self.name, self.dbid)
return u"%s(player#%s)" % (_GA(self, "name"), _GA(self, "dbid"))
# this is required to properly handle attributes and typeclass loading
_typeclass_paths = settings.PLAYER_TYPECLASS_PATHS
@ -297,15 +297,15 @@ class PlayerDB(TypedObject):
#@property
def name_get(self):
"Getter. Allows for value = self.name"
if not self._name_cache:
self._name_cache = self.user.username
return self._name_cache
if not _GA(self, "_name_cache"):
_SA(self, "_name_cache", _GA(self,"user").username)
return _GA(self, "_name_cache")
#@name.setter
def name_set(self, value):
"Setter. Allows for player.name = newname"
self.user.username = value
self.user.save() # this might be stopped by Django?
self._name_cache = value
_GA(self, "user").username = value
_GA(self, "user").save()
_SA(self, "_name_cache", value)
#@name.deleter
def name_del(self):
"Deleter. Allows for del self.name"
@ -317,9 +317,9 @@ class PlayerDB(TypedObject):
#@property
def uid_get(self):
"Getter. Retrieves the user id"
if not self._uid_cache:
self._uid_cache = self.user.id
return self._uid_cache
if not _GA(self, "_uid_cache"):
_SA(self, "_uid_cache", _GA(self, "user").id)
return _GA(self, "_uid_cache")
def uid_set(self, value):
raise Exception("User id cannot be set!")
def uid_del(self):
@ -345,9 +345,9 @@ class PlayerDB(TypedObject):
_is_superuser_cache = None
def is_superuser_get(self):
"Superusers have all permissions."
if self._is_superuser_cache == None:
self._is_superuser_cache = self.user.is_superuser
return self._is_superuser_cache
if _GA(self, "_is_superuser_cache") == None:
_SA(self, "_is_superuser_cache", _GA(self, "user").is_superuser)
return _GA(self, "_is_superuser_cache")
is_superuser = property(is_superuser_get)
#
@ -379,7 +379,7 @@ class PlayerDB(TypedObject):
"""
Swaps character, if possible
"""
return self.__class__.objects.swap_character(self, new_character, delete_old_character=delete_old_character)
return _GA(self, "__class__").objects.swap_character(self, new_character, delete_old_character=delete_old_character)
def delete(self, *args, **kwargs):
"Make sure to delete user also when deleting player - the two may never exist separately."

View file

@ -101,7 +101,7 @@ DEFAULT_NCLIENTS = 1
# time between each 'tick', in seconds, if not set on command
# line. All launched clients will be called upon to possibly do an
# action with this frequency.
DEFAULT_TIMESTEP = 5
DEFAULT_TIMESTEP = 2
# Port to use, if not specified on command line
DEFAULT_PORT = settings.TELNET_PORTS[0]
# chance of an action happening, per timestep. This helps to