{ "info": { "author": "Georg Bauer", "author_email": "gb@rfc1437.de", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: POSIX", "Programming Language :: Python" ], "description": "-*- restructuredtext -*-\n\nLinda Tuple Spaces for Python\n================================\n\nThis package implements simple Linda Tuple Spaces in Python, using\nmultiprocessing to allow writing code that makes full use of multicore\nmachines by still retaining a very simple communications API. Install\nis quite standard:\n\neasy_install lindypy\n\nor just download the sources and run setup.py install. There are testcases\nyou can run with setup.py test, too.\n\nI test and work with it under Python 2.6. Since I use multiprocessing,\nPython 2.6 is the minimum python version needed.\n\nWhat are Linda Tuple Spaces?\n-----------------------------\n\nLinda Tuple Spaces are a very nice communications abstraction for\nconcurrently running code. Processes communicate by sending tuples\ninto a big bag. Other processes register interest in some kinds of\ntuples. When a process registers interest in some kind of tuple,\nthis process will block. As soon as a matching tuple is available,\nthe process will run and will receive it.\n\nTuples can be removed from the big bag, or you can grab a tuple out\nof the bag without removing it. The tuple space makes sure that\ntuple inserts and removes are managed atomically.\n\nRead more at Wikipedia if you are interested in the topic:\n\nhttp://en.wikipedia.org/wiki/Tuple_space\n\nWhat does this package implement?\n----------------------------------\n\nThis package implements a simple tuple space for use in simple\nmultiprocess environments that are not distributed. A distributed\ntuple space is a beast far beyond this little package. I mostly\nwrote this package to have a way to work with parallel processes\nand have a much simpler communications paradigm. Especially I\nwanted to experiment a bit more with blackboard architectures\nand wanted to build on ideas I implemented with TooFPy, my\nwebservices framework. The end goal might be to sooner or later\ndeconstruct TooFPy into multiple small building blocks that can\nbe hooked together to form the original project or be used\nstandalone.\n\nTuples that are inserted and for which there is a direct interest\nare directly delivered to the interested process and not inserted\ninto the tuplespace at all. But non-consuming interests are served,\ntoo. The order on insert is as follows:\n\n- deliver to all interested non-consuming processes\n- deliver to the first interested consuming process\n- if no consuming process is there, store in tuple space\n\nAdditionally worker processes put tuples (ExceptionObject, Traceback)\ninto the tuple space if they run into an exception. The exception\nobject can be matched with exception types and the traceback is\nallready preprocessed. This is mostly meant for you to do some\nerror logging in some logger process.\n\nWhat are the problems in the code\n---------------------------------------\n\nObjects passed around via tuples through the tuple space won't keep\nidentity due to the usage of pickle - so be aware of that, since it might\nmake your code work strangely if you expect objects to keep identity.\n\nThe timeout() context manager uses signals, so you can't have multiple\ntimeouts stacked. This is mostly used in the test cases, there is a\nneed for much better timeout handling in the tuplespace object itself.\n\nCurrently there is no tuplespace locking - all is just done with pipes.\nThat way, a massive \"out\"ing process could move tuples into the gap\non clients between the timeout on receives and the unregister, as the\nunregister might take a moment for the manager to process the unregister.\nThis is mitigated by cleaning (and reinserting) tuples from a pipe\nprior to registering a new interest, but that only works if the process\ndoes regular inp/rd requests. So far I didn't come up with a good testcase\nfor triggering this. Of course you can allways say \"don't abort\ninterests\" and you should be fine, as the deregistration is done\non send then, and that only happens in the manager. The only concurrent\nmoment for deregistration to the managers activities is on aborted\ninterests.\n\nLimits - or when not to use it\n--------------------------------\n\nThe communication itself essentially uses pickles - that's how the\nmultiprocessing module works for pipes. That means tuples can only\ncontain pickleable data, so for example you can't eval closures, you need\nto have toplevel callables. Additionally the communication is a bit on\nthe heavy side due to that, so this is probably not the right solution\nif your problem needs loads of messages zipping around, it is more\ntargeted at managing worker pools where communication is needed and\nthere might be larger pools of tuples, but communication itself is\nonly a small amount of the overall work. Think \"workers for compute-heavy\nstuff that should make use of multicore machines with collecting\nintermediate results on a central blackboard\".\n\nIf you look for an actor package where you have tons of parallel (or\npseudo-parallel) work that wants to communicate with loads of messages,\nbetter look for something else. This uses heavyweight system processes\nand a comparatively heavyweight communication channel.\n\nValues are matched with equality, so you can only pattern match with\nvalues that actually define the equality functionality. And yes, if your\nequality functionality takes lots of resources, this will blow your tuple\nspace matching. Best to only match on primary data types. Non-matched\nparts of tuples can of course carry anything that can be pickled. But\nbe aware that every tuple is unpickled in the receiving process, so if\nyour unpickling takes lots of resources, again you won't be happy. Keep\nyour tuple simple and use them for coordination, massive data is best\nkept in a database that is shared in all processes.\n\nSince version 0.2 there are functional patterns - you can specify a\ncallable on your interest and it will match by being called on the\nrespective column of the tuples, so you can construct more complex\nmatches that way.\n\nAdditionally lindypy keeps all data in memory (allthough it's base could\nmaybe one day hooked to different backends and then use for example\nsqlite or some other database for persistent tuple spaces), so for now\nthe memory is the limit - if you expect millions of tuples in the tuple\nspace, maybe something else might be better for now.\n\nHow to use it\n--------------\n\nImporting things is simple, just grab anything from lindypy:\n\n>>> from lindypy import *\n\nYour workers are just normal callables, in the simplest case they\nare just functions written on global level (you can't use closures,\nas they are not pickleable - the manager for the tuplespace lives\nin a different process, though). So lets define a worker that waits\nfor any 4-item tuple and creates the sum of them and writes them\nout as a tuple with first item \"sum\".\n\n>>> def worker(ts):\n>>> while True:\n>>> t = ts.inp((object, object, object, object))\n>>> time.sleep(1.0) # this pretends some complex calculation\n>>> s = ts.inp(('sum', object))\n>>> ts.out(('sum', s[1]+sum(t)))\n\nNow we need to start a tuple space, start some workers. We\nneed to seed the sum tuple, too.\n\n>>> ts = tuplespace()\n>>> ts.out(('sum', 0))\n>>> for i in range(5):\n>>> ts.eval(worker)\n\nLets throw some tuples into the tuplespace:\n\n>>> ts.out((1,2,3,4))\n>>> ts.out((4,5,6,7))\n>>> ts.out((3,4,5,2))\n\nNow grab the resulting sum:\n\n>>> print ts.inp(('sum', object))\n\nNow we try to read something, but the tuple space is empty,\nso we will either block forever or - in this case - get a\ntimeout exception:\n\n>>> try:\n>>> with timeout(5):\n>>> ts.inp(('sum', object))\n>>> except TimeoutError:\n>>> print \"no more sums\"\n\nAnd now stop the tuplespace and kill the workers:\n\n>>> ts.shutdown()\n\nAdditionally the return value of tuplespace() can be used in\na with statement as a context manager, too. That makes lots\nof code easier to read and you don't need to handle the\nshutdown yourself. Take a look at the provided example_script.py\nfor a much more idiomatic way to work with a tuplespace.", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "http://bitbucket.org/rfc1437/lindypy/", "keywords": null, "license": "MIT/X", "maintainer": null, "maintainer_email": null, "name": "lindypy", "package_url": "https://pypi.org/project/lindypy/", "platform": "BSD,Linux,MacOS X", "project_url": "https://pypi.org/project/lindypy/", "project_urls": { "Download": "UNKNOWN", "Homepage": "http://bitbucket.org/rfc1437/lindypy/" }, "release_url": "https://pypi.org/project/lindypy/0.2/", "requires_dist": null, "requires_python": null, "summary": "Linda Tuple Spaces for Python", "version": "0.2" }, "last_serial": 794207, "releases": { "0.1": [ { "comment_text": "", "digests": { "md5": "f16eebf62231d0eb26be6d9c2b9dbe1a", "sha256": "f32dfcf21d937d024224379da5df6dffad01164562b87160a34e896881515d9c" }, "downloads": -1, "filename": "lindypy-0.1-py2.6.egg", "has_sig": false, "md5_digest": "f16eebf62231d0eb26be6d9c2b9dbe1a", "packagetype": "bdist_egg", "python_version": "2.6", "requires_python": null, "size": 21612, "upload_time": "2010-04-21T15:12:23", "url": "https://files.pythonhosted.org/packages/3c/b7/0030de145fdd187752ee2169b1ac99b06f9926ec67525722a893d4e2a7cf/lindypy-0.1-py2.6.egg" }, { "comment_text": "", "digests": { "md5": "5006634cbc5209376e8c657c9017c757", "sha256": "70f2dd5d2c2d216652cee8e9156cad3ad6ca300981ee71c33bff06d1c13c8049" }, "downloads": -1, "filename": "lindypy-0.1.tar.gz", "has_sig": false, "md5_digest": "5006634cbc5209376e8c657c9017c757", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10863, "upload_time": "2010-04-21T15:12:22", "url": "https://files.pythonhosted.org/packages/b8/78/a17345f691762cff38e008fc6bf8c1db22c6f2def4c0a55bc0e3efe52efc/lindypy-0.1.tar.gz" } ], "0.2": [ { "comment_text": "", "digests": { "md5": "13a272532ebfdd1d42f19cde7b0c42f2", "sha256": "f4fa35358eb88eebf194783297acd38b204eb4d629a49267c71811ba8db430a5" }, "downloads": -1, "filename": "lindypy-0.2-py2.6.egg", "has_sig": false, "md5_digest": "13a272532ebfdd1d42f19cde7b0c42f2", "packagetype": "bdist_egg", "python_version": "2.6", "requires_python": null, "size": 22550, "upload_time": "2011-03-07T21:11:16", "url": "https://files.pythonhosted.org/packages/e6/d6/4015bedcad867488c0d9706b2b68d010341aa1ad17923e1dc42a1022ba8b/lindypy-0.2-py2.6.egg" }, { "comment_text": "", "digests": { "md5": "451db98ee95e8eb2de4a61ddb1cdc2c7", "sha256": "d1299bed22ab0bdfa1f55b5f79c16840b0525a7ad6db8d9ea7f9b12ab69d7ccf" }, "downloads": -1, "filename": "lindypy-0.2.tar.gz", "has_sig": false, "md5_digest": "451db98ee95e8eb2de4a61ddb1cdc2c7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11389, "upload_time": "2011-03-07T21:11:13", "url": "https://files.pythonhosted.org/packages/8e/06/89486368de1ec56490c61b1fda75ea1c4387aadc713dc69c5a3990c21d2d/lindypy-0.2.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "13a272532ebfdd1d42f19cde7b0c42f2", "sha256": "f4fa35358eb88eebf194783297acd38b204eb4d629a49267c71811ba8db430a5" }, "downloads": -1, "filename": "lindypy-0.2-py2.6.egg", "has_sig": false, "md5_digest": "13a272532ebfdd1d42f19cde7b0c42f2", "packagetype": "bdist_egg", "python_version": "2.6", "requires_python": null, "size": 22550, "upload_time": "2011-03-07T21:11:16", "url": "https://files.pythonhosted.org/packages/e6/d6/4015bedcad867488c0d9706b2b68d010341aa1ad17923e1dc42a1022ba8b/lindypy-0.2-py2.6.egg" }, { "comment_text": "", "digests": { "md5": "451db98ee95e8eb2de4a61ddb1cdc2c7", "sha256": "d1299bed22ab0bdfa1f55b5f79c16840b0525a7ad6db8d9ea7f9b12ab69d7ccf" }, "downloads": -1, "filename": "lindypy-0.2.tar.gz", "has_sig": false, "md5_digest": "451db98ee95e8eb2de4a61ddb1cdc2c7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11389, "upload_time": "2011-03-07T21:11:13", "url": "https://files.pythonhosted.org/packages/8e/06/89486368de1ec56490c61b1fda75ea1c4387aadc713dc69c5a3990c21d2d/lindypy-0.2.tar.gz" } ] }