{ "info": { "author": "Nguy\u1ec5n Tu\u1ea5n Anh", "author_email": "ubolonton@gmail.com", "bugtrack_url": null, "classifiers": [], "description": "# Twisted CSP\nCommunicating sequential processes for Twisted. Channels like Go, or Clojurescript's `core.async`.\n\n**WARNING: This is currently alpha software.**\n\nThis 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.\n\n- Channel operations must happen inside \"light-weight processes\" (code flows, not actual threads).\n- Light-weight processes are spawn by calling `go`, `go_channel`, `go_deferred` or by using their decorator equivalents.\n- Most channel operations must follow the form of `yield do_sth(...)`.\n\n```python\ndef slow_pipe(input, output):\n while True:\n value = yield take(input)\n yield sleep(0.5)\n if value is None: # input closed\n close(output)\n yield stop()\n else:\n yield put(output, value)\n\ngo(slow_pipe, chan1, chan2))\n```\n\n## Examples ##\n\nFunction returning channel (http://talks.golang.org/2012/concurrency.slide#25).\n```python\ndef boring(message):\n c = Channel()\n def counter():\n i = 0\n while True:\n yield put(c, \"%s %d\" % (message, i))\n yield sleep(random.random())\n i += 1\n go(counter)\n return c\n\n\ndef main():\n b = boring(\"boring!\")\n for i in range(5):\n print \"You say: \\\"%s\\\"\" % (yield take(b))\n print \"You are boring; I'm leaving.\"\n```\n\nPingpong (http://talks.golang.org/2013/advconc.slide#6).\n```python\nclass Ball:\n hits = 0\n\n\n@process\ndef player(name, table):\n while True:\n ball = yield take(table)\n ball.hits += 1\n print name, ball.hits\n yield sleep(0.1)\n yield put(table, ball)\n\n\ndef main():\n table = Channel()\n\n player(\"ping\", table)\n player(\"pong\", table)\n\n yield put(table, Ball())\n yield sleep(1)\n```\n\nTimeout using `alts` (`select` in Go) (http://talks.golang.org/2012/concurrency.slide#35).\n```python\nc = boring(\"Joe\")\nwhile True:\n value, chan = yield alts([c, timeout(0.8)])\n if chan is c:\n print value\n else:\n print \"You're too slow.\"\n yield stop()\n```\n\n## Running the examples ##\n\nUse the `run` script, like\n```bash\n./run example.go.timeout_for_whole_conversation_using_select\n```\n\nExamples under `example/go` are ports of Go examples from:\n- http://talks.golang.org/2012/concurrency.slide\n- http://talks.golang.org/2013/advconc.slide.\n\n\n## Playing around in a REPL ##\n\n```python\nPython 2.7.5+ (default, Sep 19 2013, 13:48:49)\n[GCC 4.8.1] on linux2\nType \"help\", \"copyright\", \"credits\" or \"license\" for more information.\n>>> import thread\n>>> from csp import *\n>>> from twisted.internet import reactor\n>>> thread.start_new_thread(reactor.run, (), {\"installSignalHandlers\": False})\n140038185355008\n>>> class Ball:\n... hits = 0\n...\n>>> def player(name, table):\n... while True:\n... ball = yield take(table)\n... if ball is None: # channel's closed\n... print name, \"Ball's gone\"\n... break\n... ball.hits += 1\n... print name, ball.hits\n... yield sleep(0.1)\n... yield put(table, ball)\n...\n>>> def main():\n... table = Channel()\n... go(player, \"ping\", table)\n... go(player, \"pong\", table)\n... yield put(table, Ball())\n... yield sleep(1)\n... close(table)\n...\n>>> reactor.callFromThread(lambda: go(main))\n>>> ping 1\npong 2\nping 3\npong 4\nping 5\npong 6\nping 7\npong 8\nping 9\npong 10\nping Ball's gone\npong Ball's gone\n\n>>>\n```\n\n## Limitations ##\n\n- Does not work in a multi-threaded environment, at all (this is fixable though).\n- Channel's normal API cannot be used outside of a process (more precisely outside of the generator function of a process).\n- 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).\n- Forgetting to `yield` can cause subtle bugs.\n- Cooperative multi-processing (not sure if this is a big problem though).\n\n## TODO ##\n\n- Multiplexing, mixing, publishing/subscribing.\n- Channel operations (map, filter, reduce...).\n- Support multi-threaded environment (porting Clojure's `core.async` not Clojurescript's).\n- Write **tests**.\n- Think of a sensible error handling strategy (I think this should be decided by client code not library code though).\n + Should there be a separate error channel?\n + Should channels deliver `(result, error)` tuples?\n + Should errors be treated as special values (caught exceptions [re-thrown when taken](http://swannodette.github.io/2013/08/31/asynchronous-error-handling/))?\n- 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).\n- More documentation.\n- More examples (focusing on leveraging Twisted's rich network capabilities).\n- `put_then_callback`, `take_then_callback` execute the supplied callback in the same tick if result is immediately available. This can cause problems (especially if they are public API).\n\n## Inspiration ##\n\n- http://swannodette.github.io/2013/08/24/es6-generators-and-csp\n- https://github.com/clojure/core.async\n- https://github.com/olahol/node-csp\n\nOther Python CSP libraries:\n- http://code.google.com/p/pycsp/\n- https://github.com/python-concurrency/python-csp\n- https://github.com/stuglaser/pychan\n\nThese 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).\nTODO: More elaborate comparison.", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/ubolonton/twisted-csp", "keywords": null, "license": "EPL", "maintainer": null, "maintainer_email": null, "name": "twisted-csp", "package_url": "https://pypi.org/project/twisted-csp/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/twisted-csp/", "project_urls": { "Download": "UNKNOWN", "Homepage": "https://github.com/ubolonton/twisted-csp" }, "release_url": "https://pypi.org/project/twisted-csp/0.2.0/", "requires_dist": null, "requires_python": null, "summary": "Go-style channels for Twisted", "version": "0.2.0" }, "last_serial": 1109620, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "84a403487ccd653c561aefe3b5ae42b3", "sha256": "45b6e990474d7e1a9efdafceb19f2d0c494c84f69f0fc9672f8b0581a41e46f7" }, "downloads": -1, "filename": "twisted-csp-0.1.0.tar.gz", "has_sig": false, "md5_digest": "84a403487ccd653c561aefe3b5ae42b3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 3384, "upload_time": "2014-01-31T08:58:23", "url": "https://files.pythonhosted.org/packages/20/63/d44fce16a95eb8ced815f6a0f049e361d898ba639db1283eba7138d8a700/twisted-csp-0.1.0.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "67b06f0ec6df5df78ed173f19346fd16", "sha256": "05ac5ab3e41ca2235967ce950398270da96d0ebcd6a9e4ff41ebffd63fbd5da4" }, "downloads": -1, "filename": "twisted-csp-0.1.1.tar.gz", "has_sig": false, "md5_digest": "67b06f0ec6df5df78ed173f19346fd16", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13822, "upload_time": "2014-01-31T09:12:28", "url": "https://files.pythonhosted.org/packages/4e/ab/b9d69f61ece03dc85b121577c00445a999c2eb3f4e3e4501fef567a52b25/twisted-csp-0.1.1.tar.gz" } ], "0.1.2": [ { "comment_text": "", "digests": { "md5": "110cd978afc8a5de1ee7772c468c26d3", "sha256": "e586e34029158ec91a4f6334d0e922e8897f5f4ab1a0b86071ed3d36d3509e2f" }, "downloads": -1, "filename": "twisted-csp-0.1.2.tar.gz", "has_sig": false, "md5_digest": "110cd978afc8a5de1ee7772c468c26d3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13844, "upload_time": "2014-01-31T09:23:59", "url": "https://files.pythonhosted.org/packages/7b/04/fbc460d419fa82978355c051fed8f35e76933bb0456bd37197ef65a9de80/twisted-csp-0.1.2.tar.gz" } ], "0.1.3": [ { "comment_text": "", "digests": { "md5": "8b5eda31534b866590aca35e9b792b6b", "sha256": "ab67eaa0e391e3a7dc4f1b9ea578e69a818f2be38828562767f1ebbb92b80e92" }, "downloads": -1, "filename": "twisted-csp-0.1.3.tar.gz", "has_sig": false, "md5_digest": "8b5eda31534b866590aca35e9b792b6b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13867, "upload_time": "2014-01-31T09:27:05", "url": "https://files.pythonhosted.org/packages/0e/65/8af11f077886d02ae5da38d1988a1b24c15b99edbe04cfb61c2c31bb868b/twisted-csp-0.1.3.tar.gz" } ], "0.1.4": [ { "comment_text": "", "digests": { "md5": "ad17ede65982e546e34cd3ab7eb259f6", "sha256": "9bb54afb4336864ac4ce7043eb7369eabc4da14e2b7d4d2117bb1e254665e43e" }, "downloads": -1, "filename": "twisted-csp-0.1.4.tar.gz", "has_sig": false, "md5_digest": "ad17ede65982e546e34cd3ab7eb259f6", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13882, "upload_time": "2014-01-31T09:32:35", "url": "https://files.pythonhosted.org/packages/d5/89/9c138b8d89f5fededc43b3ca7ada96cedf10938ec465e7d96f4bfa70ec6a/twisted-csp-0.1.4.tar.gz" } ], "0.1.5": [ { "comment_text": "", "digests": { "md5": "a1c856706085f641ff9323d1dc8ff103", "sha256": "24ec006e30b48c08edd959308390d611e890d0ea2d6e32d0ce861e0ea3c2c216" }, "downloads": -1, "filename": "twisted-csp-0.1.5.tar.gz", "has_sig": false, "md5_digest": "a1c856706085f641ff9323d1dc8ff103", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13874, "upload_time": "2014-01-31T09:37:54", "url": "https://files.pythonhosted.org/packages/05/5c/e9157c83036f3eb76859b9ca915c8c37d98589134f9fb3566d393bec5ea8/twisted-csp-0.1.5.tar.gz" } ], "0.1.6": [ { "comment_text": "", "digests": { "md5": "7e38466d6280dd88e95405e7647a17f4", "sha256": "1837faf965915bc2b048e55fff135145144968cbd695f52c6d7f8ac9e4c6ae02" }, "downloads": -1, "filename": "twisted-csp-0.1.6.tar.gz", "has_sig": false, "md5_digest": "7e38466d6280dd88e95405e7647a17f4", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13867, "upload_time": "2014-01-31T09:38:11", "url": "https://files.pythonhosted.org/packages/d8/62/79147ce252155085a0111a5b6e9c02e107a13b3598d2fabb5a9f1452ac56/twisted-csp-0.1.6.tar.gz" } ], "0.1.7": [ { "comment_text": "", "digests": { "md5": "2417ee4356e7b940556d0caa6a1e49b5", "sha256": "4c8ac2ec63f23dd8a50f8b803dbb46ef5f83734e1db80f470ddd732f04dd2cac" }, "downloads": -1, "filename": "twisted-csp-0.1.7.tar.gz", "has_sig": false, "md5_digest": "2417ee4356e7b940556d0caa6a1e49b5", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13885, "upload_time": "2014-01-31T09:44:57", "url": "https://files.pythonhosted.org/packages/50/d4/318270544ff738a190ddfed8c0e938c1ff8874b8fe9027e57716c1d00534/twisted-csp-0.1.7.tar.gz" } ], "0.2.0": [ { "comment_text": "", "digests": { "md5": "0d069d1555f39f1e71733f9b3810a7ee", "sha256": "cb43afda6ecefe82a78b1027101460c02096987c4c66572e2677491c88183f9c" }, "downloads": -1, "filename": "twisted-csp-0.2.0.tar.gz", "has_sig": false, "md5_digest": "0d069d1555f39f1e71733f9b3810a7ee", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16715, "upload_time": "2014-05-31T09:40:00", "url": "https://files.pythonhosted.org/packages/fd/f4/246d21415310e3152316e98a1e9f79c9d5de7ef03e270bf5db827f497570/twisted-csp-0.2.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "0d069d1555f39f1e71733f9b3810a7ee", "sha256": "cb43afda6ecefe82a78b1027101460c02096987c4c66572e2677491c88183f9c" }, "downloads": -1, "filename": "twisted-csp-0.2.0.tar.gz", "has_sig": false, "md5_digest": "0d069d1555f39f1e71733f9b3810a7ee", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16715, "upload_time": "2014-05-31T09:40:00", "url": "https://files.pythonhosted.org/packages/fd/f4/246d21415310e3152316e98a1e9f79c9d5de7ef03e270bf5db827f497570/twisted-csp-0.2.0.tar.gz" } ] }