Are weak refs slower than strong refs?
Duncan Booth
duncan.booth at invalid.invalid
Sun Feb 25 12:12:55 EST 2007
John Nagle <nagle at animats.com> wrote:
> Are weak refs slower than strong refs? I've been considering
> making the "parent" links in BeautifulSoup into weak refs, so the
> trees will release immediately when they're no longer needed. In
> general, all links back towards the root of a tree should be weak
> refs; this breaks the loops that give reference counting trouble.
Yes, weak references are slower, but that may not be significant unless
people are following the parent links a lot: I would expect other
processing to make the overhead fairly insignificant.
Why not do a few timing tests with some typical use cases? Here's an
example which does nothing much but create and follow. Typical output:
Using proxy
100 loops, best of 3: 5.6 msec per loop
Call to dummy proxy
100 loops, best of 3: 3.11 msec per loop
Without proxy call
100 loops, best of 3: 2.71 msec per loop
------ timetest.py --------------------------------------------------------
from timeit import Timer, default_timer as timer
from weakref import proxy
class C:
'''Use a weak proxy (or whatever 'proxy' returns)'''
def __init__(self, parent=None):
self.parent = proxy(parent) if parent is not None else parent
self.child = None
def show_parents(self):
while self is not None:
# print "show_parents", id(self)
self = self.parent
def show_children(self):
while self is not None:
# print "show_children", id(self)
self = self.child
def t1(n):
base = C()
current = base
for i in range(n):
current.child = C(current)
current = current.child
base.show_children()
current.show_parents()
class D:
'''Strong parent reference'''
def __init__(self, parent=None):
self.parent = parent if parent is not None else parent
self.child = None
def show_parents(self):
while self is not None:
# print "show_parents", id(self)
self = self.parent
def show_children(self):
while self is not None:
# print "show_children", id(self)
self = self.child
def t2(n):
base = D()
current = base
for i in range(n):
current.child = D(current)
current = current.child
base.show_children()
current.show_parents()
def timetest(stmt):
repeat = 3
precision = 3
t = Timer(stmt, 'import __main__', timer)
# determine number so that 0.2 <= total time < 2.0
for i in range(1, 10):
number = 10**i
try:
x = t.timeit(number)
except:
t.print_exc()
return 1
if x >= 0.2:
break
try:
r = t.repeat(repeat, number)
except:
t.print_exc()
return 1
best = min(r)
print "%d loops," % number,
usec = best * 1e6 / number
if usec < 1000:
print "best of %d: %.*g usec per loop" % (repeat, precision, usec)
else:
msec = usec / 1000
if msec < 1000:
print "best of %d: %.*g msec per loop" % (repeat, precision,
msec)
else:
sec = msec / 1000
print "best of %d: %.*g sec per loop" % (repeat, precision,
sec)
if __name__=='__main__':
print "Using proxy"
timetest('__main__.t1(1000)')
print "Call to dummy proxy"
def proxy(x): return x
timetest('__main__.t1(1000)')
print "Without proxy call"
timetest('__main__.t2(1000)')
-------------------------------------------------------------------------
More information about the Python-list
mailing list