summaryrefslogtreecommitdiff
path: root/documentation.py
diff options
context:
space:
mode:
Diffstat (limited to 'documentation.py')
-rw-r--r--documentation.py108
1 files changed, 39 insertions, 69 deletions
diff --git a/documentation.py b/documentation.py
index 82c3ec8..6e56140 100644
--- a/documentation.py
+++ b/documentation.py
@@ -324,38 +324,30 @@ available. For instance:
``async``
--------------------------------------------
-We have just seen an examples of a simple decorator factory,
-implemented as a function returning a decorator.
-For more complex situations, it is more
-convenient to implement decorator factories as
-callable objects that can be converted into decorators.
-
-As an example, here will I show a decorator
-which is able to convert a blocking function into an asynchronous
-function. The function, when called,
-is executed in a separate thread. Moreover, it is possible to set
-three callbacks ``on_success``, ``on_failure`` and ``on_closing``,
-to specify how to manage the function call (of course the code here
-is just an example, it is not a recommended way of doing multi-threaded
-programming). The implementation is the following:
-
-$$on_success
-$$on_failure
-$$on_closing
-$$Async
-
-The decorated function returns
-the current execution thread, which can be stored and checked later, for
-instance to verify that the thread ``.isAlive()``.
-
-Here is an example of usage. Suppose one wants to write some data to
+The ``decorator`` facility can also produce a decorator starting
+from a class with the signature of a caller.
+
+As an example, here will I show a decorator which is able to convert a
+blocking function into an asynchronous function. The function, when
+called, is executed in a separate thread. This is very similar in
+spirit to the approach used in the ``concurrent.futures`` package. Of
+course the code here is just an example, it is not a recommended way
+of implementing futures. The implementation is the following:
+
+$$Future
+
+The decorated function returns a ``Future`` object, which has a ``.result()``
+method which blocks until the underlying thread finishes and returns
+the final result.
+
+Suppose one wants to write some data to
an external resource which can be accessed by a single user at once
(for instance a printer). Then the access to the writing function must
be locked. Here is a minimalistic example:
.. code-block:: python
- >>> async = decorator(Async(threading.Thread))
+ >>> async = decorator(Future)
>>> datalist = [] # for simplicity the written data are stored into a list.
@@ -373,12 +365,12 @@ be no synchronization problems since ``write`` is locked.
.. code-block:: python
>>> write("data1") # doctest: +ELLIPSIS
- <Thread(write-1, started...)>
+ <Future(write-1, started...)>
>>> time.sleep(.1) # wait a bit, so we are sure data2 is written after data1
>>> write("data2") # doctest: +ELLIPSIS
- <Thread(write-2, started...)>
+ <Future(write-2, started...)>
>>> time.sleep(2) # wait for the writers to complete
@@ -923,38 +915,12 @@ def trace(f):
return decorate(_trace, f)
-def on_success(result): # default implementation
- "Called on the result of the function"
- return result
-
-
-def on_failure(exc_info): # default implementation
- "Called if the function fails"
- pass
-
-
-def on_closing(): # default implementation
- "Called at the end, both in case of success and failure"
- pass
-
-
-class Async(object):
+class Future(threading.Thread):
"""
- A decorator converting blocking functions into asynchronous
- functions, by using threads or processes. Examples:
-
- async_with_threads = Async(threading.Thread)
- async_with_processes = Async(multiprocessing.Process)
+ A class converting blocking functions into asynchronous
+ functions by using threads.
"""
-
- def __init__(self, threadfactory, on_success=on_success,
- on_failure=on_failure, on_closing=on_closing):
- self.threadfactory = threadfactory
- self.on_success = on_success
- self.on_failure = on_failure
- self.on_closing = on_closing
-
- def __call__(self, func, *args, **kw):
+ def __init__(self, func, *args, **kw):
try:
counter = func.counter
except AttributeError: # instantiate the counter at the first call
@@ -962,17 +928,21 @@ class Async(object):
name = '%s-%s' % (func.__name__, next(counter))
def func_wrapper():
- try:
- result = func(*args, **kw)
- except:
- self.on_failure(sys.exc_info())
- else:
- return self.on_success(result)
- finally:
- self.on_closing()
- thread = self.threadfactory(None, func_wrapper, name)
- thread.start()
- return thread
+ self._result = func(*args, **kw)
+ super(Future, self).__init__(target=func_wrapper, name=name)
+ self.start()
+
+ def result(self):
+ self.join()
+ return self._result
+
+futurefactory = decorator(Future)
+
+
+@futurefactory
+def long_running(x):
+ time.sleep(1)
+ return x
def identity_dec(func):