P
Petr Jakes
Sorry for the typo in my previous posting. Of course it has to be: ....
simple liftt/push ON/OFF button....
simple liftt/push ON/OFF button....
Petr said:Sorry, I can't get in. Can you please show me, how to use your approach
on the simple push/push ON/OFF button for example please?
PS: seriously it is not a homeworkand I feel it like a shame I am
asking such a simple questions
States: ON, OFF
Transition event: "push", "lift"
transition diagram:
=========================
___ lift
| |
_V___|__
,->| ON |__
| |________| |
lift | | push
| ________ |
'--| OFF |<-'
|________|
^ |
|___|push
Cool. But unfortunately, neither version works inside a function's local namespace.How about something like
... a=compile('print "A"; state="b"','','exec'),actions = dict(
... b=compile('print "B"; state="c"','','exec'),
... c=compile('print "C"; state=None','','exec')
... )...state = 'a'
while state: eval(actions[state])
A
B
C
Good idea. But we can eliminate the dictionary lookup:
a1 = compile('print "A"; state=b1','','exec')
b1 = compile('print "B"; state=c1','','exec')
c1 = compile('print "C"; state=None','','exec')
state = a1
while state:
eval(state)
I believe the more modern approach to this is to use generators in some
way, yield each other as the next state. This way you avoid all almost
all the function call overhead (the part that takes significant time,
which is setting up the stack frame) and don't have to resort to
bytecode hacks for better performance.
Wolfgang said:Dumb question from a endless newbie scripting dilettant:
Do you have a reference to a cookbook example for this method?
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
Carl said:It turns out that generators are more efficient than the eval function
excuting bits of compiled code. About 20-25% faster.
Fredrik said:Carl Cerecke wrote:
why are you using generators to return things from a function, when
you can just return the things ?
Carl said: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.
Hm, I wonder how (all untested)Wolfgang> So basically if I want to write a long-running program in
Wolfgang> Python, it would make sense to code all functions that are
Wolfgang> likely to be called more than once as generators...
If they need to resume their calculations from where they left off after the
last yield.
If they need to resume their calculations from where they left off after the
last yield.
Wolfgang said:This was meant as a question.
Well, no, independently from that.
Just to avoid to inital overhead of the function call.
?
calls ?
I believe the more modern approach to this is to use generators in some
way, yield each other as the next state. This way you avoid all almost
all the function call overhead (the part that takes significant time,
which is setting up the stack frame)
<snip>Adding a continue statemtent after the yield statements yieldsa
speed increase. Still not as good as functions though. (about 30% slower)
Cheers,
Carl
...>>> test(1000) 0.000058
>>> test(1000) 0.000032
>>> test(1000) 0.000032
>>> test(100000) 0.000032
>>> a = list(actions(10))
>>> a ['lift', 'push', 'push', 'lift', 'push', 'lift', 'push', 'lift', 'lift', None]
>>> state = State()
>>> state.name = 'START'
>>> f = fsm(state, a)
>>> for state in f: print state.name,
Wolfgang said:The way I understand this, resuming a generator causes less overhead than the
inital overhead of a function call.
Wolfgang said:That was not what I wrote.
The way I understand this, resuming a generator causes less overhead than the
inital overhead of a function call.
Want to reply to this thread or ask your own question?
You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.