[py-svn] r11507 - py/dist/py/documentation
arigo at codespeak.net
arigo at codespeak.net
Wed Apr 27 12:06:46 CEST 2005
Author: arigo
Date: Wed Apr 27 12:06:46 2005
New Revision: 11507
Modified:
py/dist/py/documentation/greenlet.txt
Log:
Added the greenlet example from my ACCU lightning talk.
Modified: py/dist/py/documentation/greenlet.txt
==============================================================================
--- py/dist/py/documentation/greenlet.txt (original)
+++ py/dist/py/documentation/greenlet.txt Wed Apr 27 12:06:46 2005
@@ -30,6 +30,75 @@
.. _`Stackless`: http://www.stackless.com
.. _`test_generator.py`: http://codespeak.net/svn/user/arigo/greenlet/test_generator.py
+Example
+-------
+
+Let's consider a system controlled by a terminal-like console, where the user
+types commands. Assume that the input comes character by character. In such
+a system, there will typically be a loop like the following one::
+
+ def process_commands(*args):
+ while True:
+ line = ''
+ while not line.endswith('\n'):
+ line += read_next_char()
+ if line == 'quit\n':
+ print "are you sure?"
+ if read_next_char() != 'y':
+ continue # ignore the command
+ process_command(line)
+
+Now assume that you want to plug this program into a GUI. Most GUI toolkits
+are event-based. They will invoke a call-back for each character the user
+presses. [Replace "GUI" with "XML expat parser" if that rings more bells to
+you ``:-)``] In this setting, it is difficult to implement the
+read_next_char() function needed by the code above. We have two incompatible
+functions::
+
+ def event_keydown(key):
+ ??
+
+ def read_next_char():
+ ?? should wait for the next event_keydown() call
+
+You might consider doing that with threads. Greenlets are an alternate
+solution that don't have the related locking and shutdown problems. You
+start the process_commands() function in its own, separate greenlet, and
+then you exchange the keypresses with it as follows::
+
+ def event_keydown(key):
+ # jump into g_processor, sending it the key
+ g_processor.switch(key)
+
+ def read_next_char():
+ # g_self is g_processor in this simple example
+ g_self = greenlet.getcurrent()
+ # jump to the parent (main) greenlet, waiting for the next key
+ next_char = g_self.parent.switch()
+ return next_char
+
+ g_processor = greenlet(process_commands)
+ g_processor.switch(*args) # input arguments to process_commands()
+
+ gui.mainloop()
+
+In this example, the execution flow is: when read_next_char() is called, it
+is part of the g_processor greenlet, so when it switches to its parent
+greenlet, it resumes execution in the top-level main loop (the GUI). When
+the GUI calls event_keydown(), it switches to g_processor, which means that
+the execution jumps back wherever it was suspended in that greenlet -- in
+this case, to the switch() instruction in read_next_char() -- and the ``key``
+argument in event_keydown() is passed as the return value of the switch() in
+read_next_char().
+
+Note that read_next_char() will be suspended and resumed with its call stack
+preserved, so that it will itself return to different positions in
+process_commands() depending on where it was originally called from. This
+allows the logic of the program to be kept in a nice control-flow way; we
+don't have to completely rewrite process_commands() to turn it into a state
+machine.
+
+
Usage
=====
More information about the pytest-commit
mailing list