Skip to content
Back to top
View this page

# greenlet Concepts

A “greenlet” is a small independent pseudo-thread. Think about it as a small stack of frames; the outermost (bottom) frame is the initial function you called, and the innermost frame is the one in which the greenlet is currently paused.

In code, greenlets are represented by objects of class `greenlet`. These objects have a few defined attributes, and also have a `__dict__`, allowing for arbitrary user-defined attributes.

Warning

Attribute names beginning with `gr_` are reserved for this library.

## Switching greenlets

See also

Switching Between Greenlets: Passing Objects and Control

You work with greenlets by creating a number of such stacks and jumping execution between them. Jumps are never implicit: a greenlet must choose to jump to another greenlet, which will cause the former to suspend and the latter to resume where it was suspended. Jumping between greenlets is called “switching”. Similarly to `generator.send(val)`, switching may pass objects between greenlets.

## The greenlet Lifecycle

See also

Details And Examples

  Creating And Executing Greenlets

Where does execution go when a greenlet dies?

  Greenlet Parents

When you create a greenlet, it gets an initially empty stack; when you first switch to it, it starts to run a specified function, which may call other functions, switch out of the greenlet, etc. When eventually the outermost function finishes its execution, the greenlet’s stack becomes empty again and the greenlet is “dead”. Greenlets can also die of an uncaught exception, or be garbage collected (which raises an exception).

Example

Let’s quickly pull together an example demonstrating those concepts before continuing with a few more concepts.

    >>> from greenlet import greenlet

    >>> def test1():
    ...     print("[gr1] main  -> test1")
    ...     gr2.switch()
    ...     print("[gr1] test1 <- test2")
    ...     return 'test1 done'

    >>> def test2():
    ...     print("[gr2] test1 -> test2")
    ...     gr1.switch()
    ...     print("This is never printed.")

    >>> gr1 = greenlet(test1)
    >>> gr2 = greenlet(test2)
    >>> gr1.switch()
    [gr1] main  -> test1
    [gr2] test1 -> test2
    [gr1] test1 <- test2
    'test1 done'
    >>> gr1.dead
    True
    >>> gr2.dead
    False

The line `gr1.switch()` jumps to `test1`, which prints that, jumps to `test2`, and prints that, jumps back into `test1`, prints that; and then `test1` finishes and `gr1` dies. At this point, the execution comes back to the original `gr1.switch()` call, which returns the value that `test1` returned. Note that `test2` is never switched back to and so doesn’t print its final line; it is also not dead.

Having seen that, we can continue with a few more concepts.

## The Current greenlet

The greenlet that is actively running code is called the “current greenlet.” The `greenlet` object representing the current greenlet can be obtained by calling `getcurrent()`. (Note that this could be a subclass.)

As long as a greenlet is running, no other greenlet can be running. Execution must be explicitly transferred by switching to a different greenlet.

## The Main greenlet

Initially, there is one greenlet that you don’t have to create: the main greenlet. This is the only greenlet that can ever have a parent of None. The main greenlet can never be dead. This is true for every thread in a process.

Example

    >>> from greenlet import getcurrent
    >>> def am_i_main():
    ...     current = getcurrent()
    ...     return current.parent is None
    >>> am_i_main()
    True
    >>> glet = greenlet(am_i_main)
    >>> glet.switch()
    False

## Greenlet Parents

Every greenlet, except the main greenlet, has a “parent” greenlet. The parent greenlet defaults to being the one in which the greenlet was created (this can be changed at any time). In this way, greenlets are organized in a tree. Top-level code that doesn’t run in a user-created greenlet runs in the implicit main greenlet, which is the root of the tree.

The parent is where execution continues when a greenlet dies, whether by explicitly returning from its function, “falling off the end” of its function, or by raising an uncaught exception.

In the above example, both `gr1` and `gr2` have the main greenlet as a parent. Whenever one of them dies, the execution comes back to “main”.

### Uncaught Exceptions are Raised In the Parent

Uncaught exceptions are propagated into the parent, too. For example, if the above `test2()` contained a typo, it would generate a `NameError` that would kill `gr2`, and the exception would go back directly into “main”. The traceback would show `test2`, but not `test1`. Remember, switches are not calls, but transfer of execution between parallel “stack containers”, and the “parent” defines which stack logically comes “below” the current one.

    >>> def test2():
    ...    print(this_should_be_a_name_error)
    >>> gr1 = greenlet(test1)
    >>> gr2 = greenlet(test2)
    >>> gr1.switch()
    Traceback (most recent call last):
      ...
      File "<doctest default[3]>", line 1, in <module>
        gr1.switch()
      File "<doctest default[0]>", line 2, in test2
        print(this_should_be_a_name_error)
    NameError: name 'this_should_be_a_name_error' is not defined