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) # 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"] 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) # 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: if cmdsets:
# Merge all command sets into one, beginning with the lowest-prio one # Merge all command sets into one, beginning with the lowest-prio one

View file

@ -144,10 +144,12 @@ class CmdSet(object):
if key: if key:
self.key = key self.key = key
self.commands = [] self.commands = []
self.system_commands = []
self.actual_mergetype = self.mergetype self.actual_mergetype = self.mergetype
self.cmdsetobj = cmdsetobj self.cmdsetobj = cmdsetobj
# initialize system # initialize system
self.at_cmdset_creation() self.at_cmdset_creation()
self._contains_cache = {}
# Priority-sensitive merge operations for cmdsets # Priority-sensitive merge operations for cmdsets
@ -223,7 +225,13 @@ class CmdSet(object):
Returns True if this cmdset contains the given command (as defined 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' 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): def __add__(self, cmdset_b):
""" """
@ -327,18 +335,29 @@ class CmdSet(object):
cmds = [self._instantiate(c) for c in cmd] cmds = [self._instantiate(c) for c in cmd]
else: else:
cmds = [self._instantiate(cmd)] cmds = [self._instantiate(cmd)]
commands = self.commands
system_commands = self.system_commands
for cmd in cmds: for cmd in cmds:
# add all commands # add all commands
if not hasattr(cmd, 'obj'): if not hasattr(cmd, 'obj'):
cmd.obj = self.cmdsetobj cmd.obj = self.cmdsetobj
try: try:
ic = self.commands.index(cmd) ic = commands.index(cmd)
self.commands[ic] = cmd # replace commands[ic] = cmd # replace
except ValueError: except ValueError:
self.commands.append(cmd) commands.append(cmd)
# extra run to make sure to avoid doublets # 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 #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): def remove(self, cmd):
""" """
@ -369,7 +388,8 @@ class CmdSet(object):
commands starting with double underscore __. commands starting with double underscore __.
These are excempt from merge operations. 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): 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] mcs.aliases = [str(alias).strip().lower() for alias in mcs.aliases]
# optimization - a set is much faster to match against than a list # optimization - a set is much faster to match against than a list
mcs._matchset = set([mcs.key] + mcs.aliases) mcs._matchset = set([mcs.key] + mcs.aliases)
# optimization for retrieving aliases and key as one list # optimization for looping over keys+aliases
mcs._keyaliases = [mcs.key] + mcs.aliases mcs._keyaliases = tuple(mcs._matchset)
# by default we don't save the command between runs # by default we don't save the command between runs
if not hasattr(mcs, "save_for_next"): if not hasattr(mcs, "save_for_next"):

View file

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

View file

@ -637,31 +637,26 @@ class Object(TypeClass):
""" """
if not pobject: if not pobject:
return return
string = "{c%s{n" % self.name # get and identify all objects
desc = self.attr("desc") 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: if desc:
string += "\n %s" % 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: if exits:
string += "\n{wExits:{n " + ", ".join(exits) string += "\n{wExits:{n " + ", ".join(exits)
if users or things: if users or things:
string += "\n{wYou see: {n" string += "\n{wYou see:{n " + ", ".join(users + things)
if users:
string += "{c" + ", ".join(users) + "{n "
if things:
string += ", ".join(things)
return string return string
def at_desc(self, looker=None): def at_desc(self, looker=None):

View file

@ -180,9 +180,9 @@ class PlayerDB(TypedObject):
"Parent must be initiated first" "Parent must be initiated first"
TypedObject.__init__(self, *args, **kwargs) TypedObject.__init__(self, *args, **kwargs)
# handlers # handlers
self.cmdset = CmdSetHandler(self) _SA(self, "cmdset", CmdSetHandler(self))
self.cmdset.update(init_mode=True) _GA(self, "cmdset").update(init_mode=True)
self.nicks = PlayerNickHandler(self) _SA(self, "nicks", PlayerNickHandler(self))
# Wrapper properties to easily set database fields. These are # Wrapper properties to easily set database fields. These are
# @property decorators that allows to access these fields using # @property decorators that allows to access these fields using
@ -240,21 +240,21 @@ class PlayerDB(TypedObject):
#@property #@property
def cmdset_storage_get(self): def cmdset_storage_get(self):
"Getter. Allows for value = self.name. Returns a list of cmdset_storage." "Getter. Allows for value = self.name. Returns a list of cmdset_storage."
if self.db_cmdset_storage: if _GA(self, "db_cmdset_storage"):
return [path.strip() for path in self.db_cmdset_storage.split(',')] return [path.strip() for path in _GA(self, "db_cmdset_storage").split(',')]
return [] return []
#@cmdset_storage.setter #@cmdset_storage.setter
def cmdset_storage_set(self, value): def cmdset_storage_set(self, value):
"Setter. Allows for self.name = value. Stores as a comma-separated string." "Setter. Allows for self.name = value. Stores as a comma-separated string."
if utils.is_iter(value): if utils.is_iter(value):
value = ",".join([str(val).strip() for val in value]) value = ",".join([str(val).strip() for val in value])
self.db_cmdset_storage = value _SA(self, "db_cmdset_storage", value)
self.save() _GA(self, "save")()
#@cmdset_storage.deleter #@cmdset_storage.deleter
def cmdset_storage_del(self): def cmdset_storage_del(self):
"Deleter. Allows for del self.name" "Deleter. Allows for del self.name"
self.db_cmdset_storage = "" _SA(self, "db_cmdset_storage", "")
self.save() _GA(self, "save")()
cmdset_storage = property(cmdset_storage_get, cmdset_storage_set, cmdset_storage_del) cmdset_storage = property(cmdset_storage_get, cmdset_storage_set, cmdset_storage_del)
#@property #@property
@ -281,10 +281,10 @@ class PlayerDB(TypedObject):
# #
def __str__(self): 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): 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 # this is required to properly handle attributes and typeclass loading
_typeclass_paths = settings.PLAYER_TYPECLASS_PATHS _typeclass_paths = settings.PLAYER_TYPECLASS_PATHS
@ -297,15 +297,15 @@ class PlayerDB(TypedObject):
#@property #@property
def name_get(self): def name_get(self):
"Getter. Allows for value = self.name" "Getter. Allows for value = self.name"
if not self._name_cache: if not _GA(self, "_name_cache"):
self._name_cache = self.user.username _SA(self, "_name_cache", _GA(self,"user").username)
return self._name_cache return _GA(self, "_name_cache")
#@name.setter #@name.setter
def name_set(self, value): def name_set(self, value):
"Setter. Allows for player.name = newname" "Setter. Allows for player.name = newname"
self.user.username = value _GA(self, "user").username = value
self.user.save() # this might be stopped by Django? _GA(self, "user").save()
self._name_cache = value _SA(self, "_name_cache", value)
#@name.deleter #@name.deleter
def name_del(self): def name_del(self):
"Deleter. Allows for del self.name" "Deleter. Allows for del self.name"
@ -317,9 +317,9 @@ class PlayerDB(TypedObject):
#@property #@property
def uid_get(self): def uid_get(self):
"Getter. Retrieves the user id" "Getter. Retrieves the user id"
if not self._uid_cache: if not _GA(self, "_uid_cache"):
self._uid_cache = self.user.id _SA(self, "_uid_cache", _GA(self, "user").id)
return self._uid_cache return _GA(self, "_uid_cache")
def uid_set(self, value): def uid_set(self, value):
raise Exception("User id cannot be set!") raise Exception("User id cannot be set!")
def uid_del(self): def uid_del(self):
@ -345,9 +345,9 @@ class PlayerDB(TypedObject):
_is_superuser_cache = None _is_superuser_cache = None
def is_superuser_get(self): def is_superuser_get(self):
"Superusers have all permissions." "Superusers have all permissions."
if self._is_superuser_cache == None: if _GA(self, "_is_superuser_cache") == None:
self._is_superuser_cache = self.user.is_superuser _SA(self, "_is_superuser_cache", _GA(self, "user").is_superuser)
return self._is_superuser_cache return _GA(self, "_is_superuser_cache")
is_superuser = property(is_superuser_get) is_superuser = property(is_superuser_get)
# #
@ -379,7 +379,7 @@ class PlayerDB(TypedObject):
""" """
Swaps character, if possible 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): def delete(self, *args, **kwargs):
"Make sure to delete user also when deleting player - the two may never exist separately." "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 # time between each 'tick', in seconds, if not set on command
# line. All launched clients will be called upon to possibly do an # line. All launched clients will be called upon to possibly do an
# action with this frequency. # action with this frequency.
DEFAULT_TIMESTEP = 5 DEFAULT_TIMESTEP = 2
# Port to use, if not specified on command line # Port to use, if not specified on command line
DEFAULT_PORT = settings.TELNET_PORTS[0] DEFAULT_PORT = settings.TELNET_PORTS[0]
# chance of an action happening, per timestep. This helps to # chance of an action happening, per timestep. This helps to