diff options
| author | Jason Madden <jamadden@gmail.com> | 2020-11-18 16:39:19 -0600 |
|---|---|---|
| committer | Jason Madden <jamadden@gmail.com> | 2020-11-18 16:39:19 -0600 |
| commit | ac501f92a9ef5f3ec80b938647bb3f4919b4e924 (patch) | |
| tree | 41481f5e4676a50ecbd5a379e571378cff3d219d /docs/creating_executing_greenlets.rst | |
| parent | b71ab28391a4c5478018051252cd85008711cd63 (diff) | |
| download | greenlet-ac501f92a9ef5f3ec80b938647bb3f4919b4e924.tar.gz | |
More docs.
Diffstat (limited to 'docs/creating_executing_greenlets.rst')
| -rw-r--r-- | docs/creating_executing_greenlets.rst | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/docs/creating_executing_greenlets.rst b/docs/creating_executing_greenlets.rst new file mode 100644 index 0000000..81d0cb6 --- /dev/null +++ b/docs/creating_executing_greenlets.rst @@ -0,0 +1,169 @@ +========================================================== + Creating And Executing Greenlets: The Greenlet Lifecycle +========================================================== + +.. currentmodule:: greenlet + +To create a new greenlet, simply instantiate a new object of class +:class:`greenlet.greenlet`, passing it the initial function to run. + +.. tip:: + + If you're using a framework built on greenlets, such as + :mod:`gevent`, consult its documentation. Some frameworks have + other ways of creating new greenlets (for example, + :func:`gevent.spawn`) or prefer a different greenlet class (for + example, :class:`gevent.Greenlet`). + +.. doctest:: + + >>> import greenlet + >>> def run(): + ... print("Running in the greenlet function.") + >>> glet = greenlet.greenlet(run) + +The greenlet will have its ``run`` attribute set to the function you +passed, and its :ref:`parent <greenlet_parents>` will be the +:func:`current greenlet <getcurrent>`. + +.. doctest:: + + >>> glet.run is run + True + >>> glet.parent is greenlet.getcurrent() + True + +Execution of the greenlet begins when :meth:`greenlet.switch` is +called on it. + +.. doctest:: + + >>> glet.switch() + Running in the greenlet function. + +The ``run`` attribute is deleted at that time. + +.. doctest:: + + >>> glet.run + Traceback (most recent call last): + ... + AttributeError: run + +You can also subclass :class:`greenlet.greenlet` and define ``run`` as +a method. This is useful to store additional state with the greenlet. + +.. doctest:: + + >>> import time + >>> class MyGreenlet(greenlet.greenlet): + ... created_at = None + ... finished_at = None + ... def run(self): + ... self.created_at = time.time() + ... print("Running in the greenlet subclass.") + ... self.finished_at = time.time() + >>> glet = MyGreenlet() + >>> glet.switch() + Running in the greenlet subclass. + >>> glet.finished_at >= glet.created_at + True + +See :ref:`switching` for more information about switching into greenlets. + +Changing The Parent +=================== + +When a greenlet finishes, execution resumes with its parent. This +defaults to the current greenlet when the object was instantiated, but +can be changed either at that time or any time later. To set it at +creation time, pass the desired parent as the second argument: + +.. doctest:: + + >>> def parent(child_result): + ... print("In the parent.") + >>> parent_glet = greenlet.greenlet(parent) + >>> def child(): + ... print("In the child.") + >>> child_glet = greenlet.greenlet(child, parent_glet) + >>> child_glet.switch() + In the child. + In the parent. + +To change it later, assign to the :attr:`greenlet.parent` attribute. + +.. doctest:: + + >>> parent_glet = greenlet.greenlet(parent) + >>> child_glet = greenlet.greenlet(child) + >>> child_glet.parent = parent_glet + >>> child_glet.switch() + In the child. + In the parent. + +Of course, cycles are not permitted. + +.. doctest:: + + >>> parent_glet = greenlet.greenlet(parent) + >>> child_glet = greenlet.greenlet(child) + >>> child_glet.parent = parent_glet + >>> parent_glet.parent = child_glet + Traceback (most recent call last): + ... + ValueError: cyclic parent chain + +The parent must be a greenlet. + +.. doctest:: + + >>> parent_glet.parent = 42 + Traceback (most recent call last): + ... + TypeError: parent must be a greenlet + +Interrupting Greenlets by Throwing Exceptions +============================================= + +Besides simply :meth:`switching <greenlet.switch>` into a greenlet, +you can also have it resume execution by throwing an exception into +it. This is useful to interrupt a loop in the greenlet, for instance. + +.. doctest:: + + >>> main = greenlet.getcurrent() + >>> class MyException(Exception): + ... pass + >>> def run(): + ... try: + ... main.switch() + ... except MyException: + ... print("Caught exception in greenlet.") + >>> glet = greenlet.greenlet(run) + >>> _ = glet.switch() + >>> glet.throw(MyException) + Caught exception in greenlet. + +Uncaught exceptions thrown into the greenlet will propagate into the +parent greenlet. + +.. doctest:: + + >>> glet = greenlet.greenlet(run) + >>> _ = glet.switch() + >>> glet.throw(ValueError) + Traceback (most recent call last): + ... + ValueError + +As a special case, if the uncaught exception is +:exc:`greenlet.GreenletExit`, it will *not* propagate but instead be +returned. This is commonly used to signal an "expected exit". + +.. doctest:: + + >>> glet = greenlet.greenlet(run) + >>> _ = glet.switch() + >>> glet.throw(greenlet.GreenletExit) + GreenletExit() |
