goless: Go-style Python
For an example of what goless can do, here is the Go program at https://gobyexample.com/select reimplemented with goless:
c1 = goless.chan() c2 = goless.chan() def func1(): time.sleep(1) c1.send('one') goless.go(func1) def func2(): time.sleep(2) c2.send('two') goless.go(func2) for i in range(2): case, val = goless.select([goless.rcase(c1), goless.rcase(c2)]) print(val)
It is surely a testament to Go's style that it isn't much less Python code than Go code, but I quite like this. Don't you?
The :func:`goless.go` function mimics Go's goroutines by, unsurprisingly, running the routine in a tasklet/greenlet. If an unhandled exception occurs in a goroutine, :func:`goless.on_panic` is called.
.. autofunction:: goless.go
.. autofunction:: goless.on_panic
There are three types of channels available in
Use the :func:`goless.chan` function to create a channel.
The channel implementations contain more thorough documentation
about how they actually work.
.. autofunction:: goless.chan
.. autoclass:: goless.channels.GoChannel :members: send, recv, close
.. autoclass:: goless.ChannelClosed
The select function
select statement is implemented through the :func:`goless.select` function.
Because Python lacks anonymous blocks (multiline lambdas),
:func:`goless.select` works like Go's reflect.Select function.
Callers should create any number of :class:`goless.case` classes
that are passed into :func:`goless.select`.
The function returns the chosen case, which the caller will usually switch off of.
chan = goless.chan() cases = [goless.rcase(chan), goless.scase(chan, 1), goless.dcase()] chosen, value = goless.select(cases) if chosen is cases: print('Received %s' % value) elif chosen is cases: assert value is None print('Sent.') else: assert chosen is cases print('Default...')
Callers should never have to do anything with cases, other than create and switch off of them.
.. autofunction:: goless.select
.. autoclass:: goless.dcase
.. autoclass:: goless.rcase
.. autoclass:: goless.scase
Exception handling is a tricky topic and may change in the future.
The default behavior right now is that an unhandled exception in a goroutine will
log the exception and take down the entire process.
This in theory emulates Go's
if a goroutine panics, the process will exit.
If you are not happy with this behavior, you should patch goless.on_panic to provide custom behavior.
If you find a better pattern, create an issue on GitHub.
examples/ folder contains a number of examples.
there are many examples from http://gobyexample.com implemented
goless in the
If there is an example you'd like to see, or an idiomatic Go example you'd like converted, please see :ref:`a-contrib` below.
You can run benchmarks using the current Python interpreter and configured
backend by running the following from the
goless project directory:
$ python -m benchmark
Developers may run benchmarks locally and report them into the following table. The Go versions of the benchmarks are also run. The numbers are useful for relative comparisons only:
To regenerate this table, run:
$ python write_benchmarks.py
To print the table to stdout, run (notice the trailing
$ python write_benchresults.py -
Assuming you have Go installed, you can run the benchmarks with:
$ go run benchmark.go
There are two backends for concurrently available in
Backends should only be used by
and not by any client code.
You can choose between backends by setting the environment variable
Otherwise, an appropriate backend will be chosen.
stackless are available,
goless will raise an error when used (but will still be importable).
The good news is that you probably don't need to worry about any of this, and goless works almost everywhere.
The bad news is, almost all abstractions are leaky,
and there can be some nuances to compatibility.
If you run into an issue where
goless cannot create a backend,
you may need to read the following sections.
goless works under PyPy out of the box with the stackless
backend, because PyPy includes a
stackless.py file in its standard library.
This appears to work properly, but fails the
goless test suite.
We are not sure why yet, as
stackless.py does not have a real maintainer
and the bug is difficult to track down.
However, the examples and common usages seem to all work fine.
Using PyPy 2.2+ and the tip of gevent's GitHub repo ( https://github.com/surfly/gevent ), the gevent backend works and is fully tested.
Python 2 (CPython)
Using Python 2 and the CPython interpreter,
you can use the gevent backend for
with no problems.
Under Python 2, you can just do:
$ pip install gevent $ pip install goless
Python 3 (CPython)
Newer versions of gevent include Python 3 compatibility.
To install gevent on Python3, you also must install Cython.
So you can use thew following commands to install
under Python3 with its gevent backend:
$ pip install cython $ pip install git+https://github.com/surfly/gevent.git#gevent-egg $ pip install goless
This works and is tested.
All versions of Stackless Python (2 and 3) should work with goless. However, we cannot test with Stackless Python on Travis, so we only test with it locally. If you find any problems, please report an issue.
goless and the GIL
goless does not address CPython's Global Interpreter Lock (GIL) at all.
goless does not magically provide any parallelization.
It provides Go-like semantics, but not its performance.
Perhaps this will change in the future if the GIL is removed.
Another option is PyPy's STM branch,
goless will (probably) benefit heartily.
- goless on GitHub: https://github.com/rgalanakis/goless
- goless on Read the Docs: http://goless.readthedocs.org/
- goless on Travis-CI: https://travis-ci.org/rgalanakis/goless
- goless on Coveralls: https://coveralls.io/r/rgalanakis/goless
- The Go Programming Language: http://www.golang.org
- Stackless Python: http://www.stackless.com
- gevent: http://gevent.org/
- PyPy: http://pypy.org/
- Idiomatic Go Examples: http://gobyexample.com
I am definitely not a Go expert, so improvements to make things more idiomatic are very welcome. Please create an issue or pull request on GitHub: https://github.com/rgalanakis/goless
goless was created by a number of people at the PyCon 2014 sprints.
Even a small library like
goless is the product of lots of collaboration.
- Rob Galanakis <firstname.lastname@example.org>
- Simon König <email@example.com>
- Carlos Knippschild <firstname.lastname@example.org>
Coverage is wrong. It should be higher. The coverage module does not work properly with gevent and stackless.