Overhead for local assignments (was: A better self)
Louis M. Pecora
pecora at anvil.nrl.navy.mil
Tue Jul 23 12:11:00 EDT 2002
I did some tests as suggested in the "Better self" thread on the timing
overhead of assigning to local variables and then using them in a
formula. The issue in that thread was readability which can be gained
several ways. The code and results below compares those ways. I
present the explanation for the four tests, first, then show the
results (a bit surprising...to me, at least), and then at the end I
give the code. I am not claiming this is the best way to do these
tests. It is typical of coding I have done. Feel free to criticize or
better, suggest other tests, or even better, do other tests and post
them.
-- Lou Pecora
EXPLANATION OF TESTS =====================================
# Tests overhead for "assigning" object variables
# (e.g. self.t, self.x, self.y, self.z) to
# local variables or function arguments so as to use simpler names
# in a formula without the "self." prefix. Such assignements
# will cause "overhead". This module's aim is to compare the
# overhead involved in each approach.
# The approaches are:
# (1) Assign in tuple, thus: t,x,y,z=self.t,self.x,self.y,self.z,
# then use t,x,y, and z in the formula
# (2) Assign in line, thus: t=self.t
# x=self.x
# y=self.y
# z=self.z, then use t,x,y, and z
# in the formula
# (3) Assign to class function arguments, thus:
# self.fcntst(self.t,self.x,self.y,self.z),
# where the class function contains the formula
# (4) Assign to class function arguments using local
# variable f assigned to the class function, thus:
# f(self.t,self.x,self.y,self.z), where f=self.fcntst
#
# Note, an attempt is made to _exclude_ the loop overhead by
# timing an empty xrange loop, first, and subtracting that
# time, tx, from the tests (1) to (4)
RESULTS AND COMMENTS =====================================
Note: the results (the ratios) appeared to be independent of the
number of loops used (n, below) from n=1000 to n=1000000
xRange time= 0.15076
tuple assign time= 0.958203999999
line time= 0.799539
fcn1 (class call) time= 1.508272
fcn2 (local call) time= 1.256834
Ratios to the minimum time:
(1): 1.24455939542
(2): 1.0
(3): 2.09241051267
(4): 1.70485481189
Method (2) is fastest as some people suggested. (1) does seem to
involve some time creating and destroying a tuple as suggested. (3) is
the worst, by a factor of 2! So if you have lots of class function
calls, assign the function to a local variable, but even better, avoid
using the function calls to just calculate a formula, if possible.
CODE =====================================
# Just imports stuff commonly used
import time
from Numeric import *
class lcltst:
def __init__(self,n):
self.t=1
self.x=2
self.y=3
self.z=4
self.n=n # Numb.loops
# Calculate the for loop time so as to exclude it later
t1=time.clock()
for i in xrange(self.n):
pass
self.tx=time.clock()-t1 # loop time
print "xRange time=",self.tx
# (1) Assign variables in a tuple
def linasg(self):
t1=time.clock()
for i in xrange(self.n):
t,x,y,z=self.t,self.x,self.y,self.z
# After assigning local variables normally the
# formula for doing
# calculations using the local variables would follow
t2=time.clock()
print "tuple assign time=",t2-t1
return t2-t1
# (2) Assign variables one at a time, in line
def indasg(self):
t1=time.clock()
for i in xrange(self.n):
t=self.t
x=self.x
y=self.y
z=self.z
# After assigning local variables normally the
# formula for doing
# calculations using the local variables would follow
t2=time.clock()
print "line time=",t2-t1
return t2-t1
# Dummy function
def fcntst(self,t,x,y,z):
# Would normally contain the formula and do calculations using
# the argument variables
pass
# (3) Call dummy formula function
def fcn1(self):
t1=time.clock()
for i in xrange(self.n):
# Use class function call
self.fcntst(self.t,self.x,self.y,self.z)
t2=time.clock()
print "fcn1 (class call) time=",t2-t1
return t2-t1
# (4) Call local assignment of dummy formula function
def fcn2(self):
t1=time.clock()
# Assign class function to local variable, first
f=self.fcntst
for i in xrange(self.n):
f(self.t,self.x,self.y,self.z)
t2=time.clock()
print "fcn2 (local call) time=",t2-t1
return t2-t1
#---- Run the test for n loops ----------------------------
print "--------------------------------------"
n=200000 # Number of loops (tested from n=1000, to n=1000000)
lt=lcltst(n)
tx=lt.tx
tlist=[lt.linasg()-tx]
tlist=tlist+[lt.indasg()-tx]
tlist=tlist+[lt.fcn1()-tx]
tlist=tlist+[lt.fcn2()-tx]
tmax=min(tlist)
tfract=divide(tlist,tmax)
print
print "Ratios to the minimum time:"
print "(1):",tfract[0]
print "(2):",tfract[1]
print "(3):",tfract[2]
print "(4):",tfract[3]
More information about the Python-list
mailing list