Skip to content
Back to top
View this page

# Creating And Executing Greenlets

To create a new greenlet, simply instantiate a new object of class `greenlet.greenlet`, passing it the initial function to run.

Tip

If you’re using a framework built on greenlets, such as `gevent`, consult its documentation. Some frameworks have other ways of creating new greenlets (for example, `gevent.spawn()`) or prefer a different greenlet class (for example, `gevent.Greenlet`).

    >>> 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 parent will be the `current greenlet`.

    >>> glet.run is run
    True
    >>> glet.parent is greenlet.getcurrent()
    True

Execution of the greenlet begins when `greenlet.switch()` is called on it.

    >>> glet.switch()
    Running in the greenlet function.

The `run` attribute is deleted at that time.

    >>> glet.run
    Traceback (most recent call last):
    ...
    AttributeError: run

## Subclassing greenlet

You can also subclass `greenlet.greenlet` and define `run` as a method. This is useful to store additional state with the greenlet.

    >>> 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 Switching Between Greenlets: Passing Objects and Control 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:

    >>> 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 `greenlet.parent` attribute.

    >>> 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.

    >>> 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.

    >>> parent_glet.parent = 42
    Traceback (most recent call last):
    ...
    TypeError: parent must be a greenlet

## Interrupting Greenlets by Throwing Exceptions

Besides simply `switching` 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.

    >>> 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.

    >>> glet = greenlet.greenlet(run)
    >>> _ = glet.switch()
    >>> glet.throw(ValueError)
    Traceback (most recent call last):
    ...
    ValueError

As a special case, if the uncaught exception is `greenlet.GreenletExit`, it will not propagate but instead be returned. This is commonly used to signal an “expected exit”.

    >>> glet = greenlet.greenlet(run)
    >>> _ = glet.switch()
    >>> glet.throw(greenlet.GreenletExit)
    GreenletExit()