Weird generator id() behaviour (was Re: Python code written in1998, how to improve/change it?)
Carl Cerecke
cdc at maxnet.co.nz
Tue Jan 24 18:04:47 EST 2006
Fredrik Lundh wrote:
> Carl Cerecke wrote:
>
>
>>It turns out that generators are more efficient than the eval function
>>excuting bits of compiled code. About 20-25% faster.
>
>
> why are you using generators to return things from a function, when
> you can just return the things ?
Trying to find the fastest way to implement finite state machine.
The included file times 4 different ways, with functions the fastest.
The reason, I think, for the unusual sequence if id()s of the generators
- see grandparent post - (and the reason for their poor performance
compared to functions), is because the reference to the generator is
being lost, then another generator is being created with the same id.
Properly done, I would expect generators to out perform functions.
These are the numbers I get on a P3 600:
$ ./foo.py
action generator overhead: 13.25
---
exec: 8.7
---
eval: 10.09
---
generators: 6.68
---
functions: 3.37
#!/usr/bin/env python
import time
s_on = compile('''
#print 'on'
action = next_action()
if action == 'lift':
state = s_on
elif action == 'push':
state = s_off
else:
state = None
''','','exec')
s_off = compile('''
#print 'off'
action = next_action()
if action == 'lift':
state = s_on
elif action == 'push':
state = s_off
else:
state = None
''','','exec')
def f_on():
action = next_action()
if action == 'lift':
return f_on
elif action == 'push':
return f_off
else:
return None
def f_off():
action = next_action()
if action == 'lift':
return f_on
elif action == 'push':
return f_off
else:
return None
def g_on():
#print "on"
action = next_action()
if action == 'lift':
yield g_on()
elif action == 'push':
yield g_off()
else:
yield None
def g_off():
#print "off"
action = next_action()
if action == 'lift':
yield g_on()
elif action == 'push':
yield g_off()
else:
yield None
def actions(n):
import random
for i in range(n-1):
yield random.choice(['lift','push'])
yield None
r = 1000000
#r = 10
next_action = actions(r).next
a = time.clock()
while next_action():
pass
z = time.clock()
print "action generator overhead:",z-a
common = z-a
print "---"
next_action = actions(r).next
state = s_on # start state
a = time.clock()
while state:
exec state
z = time.clock()
print "exec:",z-a-common
print "---"
next_action = actions(r).next
state = s_on # start state
a = time.clock()
while state:
eval(state)
z = time.clock()
print "eval:",z-a-common
print "---"
next_action = actions(r).next
s_g_on = g_on()
s_g_off = g_off()
state = s_g_on
a = time.clock()
while state:
#print id(state)
state = state.next()
z = time.clock()
print "generators:",z-a-common
print "---"
next_action = actions(r).next
state = f_on
a = time.clock()
while state:
state = state()
z = time.clock()
print "functions:",z-a-common
More information about the Python-list
mailing list