Metadata-Version: 1.0
Name: twisted-csp
Version: 0.1.6
Summary: Go-style channels for Twisted
Home-page: https://github.com/ubolonton/twisted-csp
Author: Nguyễn Tuấn Anh
Author-email: ubolonton@gmail.com
License: EPL
Description: # Twisted CSP
        Communicating sequential processes for Twisted. Channels like Go, or Clojurescript's `core.async`.
        
        **WARNING: This is currently alpha  software.**
        
        This is a very close port of Clojurescript's `core.async`. The significant difference is that light-weight processes are implemented using generators (`yield`) instead of macros.
        
        - Channel operations must happen inside "light-weight processes" (code flows, not actual threads).
        - Light-weight processes are spawn by calling `go` on generators.
        - Most channel operations must follow the form of `yield do_sth(...)`.
        
        ```python
        def slow_pipe(input, output):
            while True:
                value = yield take(input)
                yield wait(0.5)
                if value is None: # input closed
                    close(output)
                    yield stop()
                else:
                    yield put(output, value)
        
        go(slow_pipe(chan1, chan2))
        ```
        
        ## Examples ##
        
        Function returning channel (http://talks.golang.org/2012/concurrency.slide#25).
        ```python
        def boring(message):
            c = Channel()
            def counter():
                i = 0
                while True:
                    yield put(c, "%s %d" % (message, i))
                    yield wait(random.random())
                    i += 1
            go(counter())
            return c
        
        
        def main():
            b = boring("boring!")
            for i in range(5):
                print "You say: \"%s\"" % (yield take(b))
            print "You are boring; I'm leaving."
        ```
        
        Pingpong (http://talks.golang.org/2013/advconc.slide#6).
        ```python
        class Ball:
            hits = 0
        
        
        def player(name, table):
            while True:
                ball = yield take(table)
                ball.hits += 1
                print name, ball.hits
                yield wait(0.1)
                yield put(table, ball)
        
        
        def main():
            table = Channel()
        
            go(player("ping", table))
            go(player("pong", table))
        
            yield put(table, Ball())
            yield wait(1)
        ```
        
        Timeout using `alts` (`select` in Go) (http://talks.golang.org/2012/concurrency.slide#35).
        ```python
        c = boring("Joe")
        while True:
            value, chan = yield alts([c, timeout(0.8)])
            if chan is c:
                print value
            else:
                print "You're too slow."
                yield stop()
        ```
        
        ## Running the examples ##
        
        Use the `run` script, like
        ```bash
        ./run example.go.timeout_for_whole_conversation_using_select
        ```
        
        Examples under `example/go` are ports of Go examples from:
        - http://talks.golang.org/2012/concurrency.slide
        - http://talks.golang.org/2013/advconc.slide.
        
        
        ## Playing around in a REPL ##
        
        ```python
        Python 2.7.5+ (default, Sep 19 2013, 13:48:49)
        [GCC 4.8.1] on linux2
        Type "help", "copyright", "credits" or "license" for more information.
        >>> import thread
        >>> from csp import *
        >>> from twisted.internet import reactor
        >>> thread.start_new_thread(reactor.run, (), {"installSignalHandlers": False})
        140038185355008
        >>> class Ball:
        ...     hits = 0
        ...
        >>> def player(name, table):
        ...     while True:
        ...         ball = yield take(table)
        ...         if ball is None: # channel's closed
        ...             print name, "Ball's gone"
        ...             break
        ...         ball.hits += 1
        ...         print name, ball.hits
        ...         yield wait(0.1)
        ...         yield put(table, ball)
        ...
        >>> def main():
        ...     table = Channel()
        ...     go(player("ping", table))
        ...     go(player("pong", table))
        ...     yield put(table, Ball())
        ...     yield wait(1)
        ...     close(table)
        ...
        >>> reactor.callFromThread(lambda: go(main()))
        >>> ping 1
        pong 2
        ping 3
        pong 4
        ping 5
        pong 6
        ping 7
        pong 8
        ping 9
        pong 10
        ping Ball's gone
        pong Ball's gone
        
        >>>
        ```
        
        ## Limitations ##
        
        - Does not work in a multi-threaded environment, at all (this is fixable though).
        - Channel's normal API cannot be used outside of a process (more precisely outside of the generator function of a process).
        - Generator functions must be used to spawn processes. This makes it less composable than in Go (where the constructs are built-in), or Clojurescript (where macros rule).
        - Forgetting to `yield` can cause subtle bugs.
        - Cooperative multi-processing (not sure if this is a big problem though).
        
        ## TODO ##
        
        - Multiplexing, mixing, publishing/subscribing.
        - Channel operations (map, filter, reduce...).
        - Support multi-threaded environment (porting Clojure's `core.async` not Clojurescript's).
        - Write **tests**.
        - Think of a sensible error handling strategy (I think this should be decide by client code not library code though).
          + Should there be a separate error channel?
          + Should channels deliver `(result, error)` tuples?
          + Should error be treated as special value (caught exception [re-thrown when taken](http://swannodette.github.io/2013/08/31/asynchronous-error-handling/))?
        - Support other reactors, e.g. [Tornado](http://www.tornadoweb.org/en/stable/) (should be easy, as the dispatcher is the only thing that depends on twisted).
        - More documentation.
        - More examples (focusing on leveraging Twisted's rich network capabilities).
        - Upload to PyPi.
        
        ## Inspiration ##
        
        - http://swannodette.github.io/2013/08/24/es6-generators-and-csp
        - https://github.com/clojure/core.async
        - https://github.com/olahol/node-csp
        
        Other Python CSP libraries:
        - http://code.google.com/p/pycsp/
        - https://github.com/python-concurrency/python-csp
        - https://github.com/stuglaser/pychan
        
        These libraries use threads/processes (except for pycsp, which has support for greenlets (which is not portable)). This makes implementation simpler (in principle), sacrificing efficiency (but managing threads/processes can be a chore). On the other hand they are much more generic, and support networked channels (that is not necessarily a good thing though).
        TODO: More elaborate comparison.
        
Platform: UNKNOWN
