Optimize FlatNodeMap update of _hndl2index for add/delete

tests with python2.6 and python3 show that it's much quicker to get
the handles after the inser/deleted index and upgrade those
(because random-access in a hash-table is super fast)

Here is the code use for tests:

import string,random,sys
import timeit

def id_generator(size=6, chars=string.ascii_lowercase):
    return ''.join(random.choice(chars) for _ in range(size))

num_items=80000
handle_sizes=10
num_operation=2000
setup="""
from __main__ import id_generator,string,num_items,handle_sizes,random
_index2hndl=[("",id_generator(handle_sizes)) for e in range (num_items)]
_hndl2index=dict([key[1], index]
                for index, key in enumerate(_index2hndl))
"""

add0='''
h=id_generator(handle_sizes)
insert_pos= random.randrange(len(_hndl2index))
srtkey_hndl=("",h)
_index2hndl.insert(insert_pos, srtkey_hndl)
for hndl, index in _hndl2index.iteritems():
    if index >= insert_pos:
        _hndl2index[hndl] += 1
_hndl2index[h]=insert_pos
'''
add1='''
h=id_generator(handle_sizes)
insert_pos= random.randrange(len(_hndl2index))
srtkey_hndl=("",h)
_index2hndl.insert(insert_pos, srtkey_hndl)
for hndl, index in _hndl2index.items():
    if index >= insert_pos:
        _hndl2index[hndl] += 1
_hndl2index[h]=insert_pos
'''
add2='''
h=id_generator(handle_sizes)
insert_pos= random.randrange(len(_hndl2index))
srtkey_hndl=("",h)
_index2hndl.insert(insert_pos, srtkey_hndl)
for srt_key,hndl in _index2hndl[insert_pos+1:]:
    _hndl2index[hndl] += 1
_hndl2index[h]=insert_pos
'''
del0='''
index= random.randrange(len(_hndl2index))
srt_key,handle=_index2hndl[index]
del _index2hndl[index]
del _hndl2index[handle]
for key, val in _hndl2index.iteritems():
    if val > index:
        _hndl2index[key] -= 1
'''
del1='''
index= random.randrange(len(_hndl2index))
srt_key,handle=_index2hndl[index]
del _index2hndl[index]
del _hndl2index[handle]
for key, val in _hndl2index.items():
    if val > index:
        _hndl2index[key] -= 1
'''
del2='''
index= random.randrange(len(_hndl2index))
srt_key,handle=_index2hndl[index]
del _index2hndl[index]
del _hndl2index[handle]
for srt_key,hndl in _index2hndl[index:]:
    _hndl2index[hndl] -= 1
'''
if sys.version_info[0] < 3:
    cmds=[add0,add1,add2,del0,del1,del2]
else:
    cmds=[add1,add2,del1,del2]
for c in cmds:
    print(c)
    random.seed(1)
    t=timeit.Timer(c, setup=setup).timeit(num_operation)
    print(num_operation,"ops in ", t, "seconds. avg:",t/num_operation,"seconds")
This commit is contained in:
Bastien Jacquet 2014-11-13 05:36:48 +01:00
parent a52a931b57
commit 48eb2842ee

View File

@ -200,7 +200,7 @@ class FlatNodeMap(object):
else:
self.__corr = (0, 1)
if not self._hndl2index:
self._hndl2index = dict([key[1], index]
self._hndl2index = dict((key[1], index)
for index, key in enumerate(self._index2hndl))
def real_path(self, index):
@ -398,13 +398,7 @@ class FlatNodeMap(object):
insert_pos = bisect.bisect_left(self._index2hndl, srtkey_hndl)
self._index2hndl.insert(insert_pos, srtkey_hndl)
#make sure the index map is updated
if sys.version_info[0] < 3: # keep this, for speed in Python2
for hndl, index in self._hndl2index.iteritems(): # in Python2 "if"
if index >= insert_pos:
self._hndl2index[hndl] += 1
else:
for hndl, index in self._hndl2index.items():
if index >= insert_pos:
for srt_key,hndl in self._index2hndl[insert_pos+1:]:
self._hndl2index[hndl] += 1
self._hndl2index[srtkey_hndl[1]] = insert_pos
#update self.__corr so it remains correct
@ -447,14 +441,8 @@ class FlatNodeMap(object):
if self._reverse:
self.__corr = (len(self._index2hndl) - 1, -1)
#update the handle2path map so it remains correct
if sys.version_info[0] < 3: # keep this, for speed in Python2
for key, val in self._hndl2index.iteritems(): # in Python2 "if"
if val > index:
self._hndl2index[key] -= 1
else:
for key, val in self._hndl2index.items():
if val > index:
self._hndl2index[key] -= 1
for srt_key,hndl in self._index2hndl[index:]:
self._hndl2index[hndl] -= 1
return Gtk.TreePath((delpath,))
#-------------------------------------------------------------------------