1.. _async:
2
3Asynchronous Operation
4======================
5Many times, especially when working in a client-server model, you may want to perform
6operations "in the background", i.e., send a batch of work to the server and continue
7with your local operation. At some later point, you may want to poll for the completion
8of the work, or perhaps be notified of its completion using a callback function.
9
10RPyC is very well-suited for asynchronous work. In fact, the protocol itself is asynchronous,
11and synchronicity is layered on top of that -- by issuing an asynchronous request and waiting
12for its completion. However, since the synchronous modus-operandi is the most common one,
13the library exposes a synchronous interface, and you'll need to explicitly enable
14asynchronous behavior.
15
16async_()
17--------
18The wrapper :func:`~rpyc.utils.helpers.async_` takes any *callable*
19:ref:`netref <api-netref>` and returns an asynchronous-wrapper around that netref.
20When invoked, this wrapper object dispatches the request and immediately returns an
21:class:`~rpyc.core.async_.AsyncResult`, instead of waiting for the response.
22
23Usage
24^^^^^
25Create an async wrapper around the server's ``time.sleep`` function ::
26
27    async_sleep = rpyc.async_(conn.modules.time.sleep)
28
29And invoke it like any other function, but instead of blocking, it will immediately
30return an ``AsyncResult`` ::
31
32    res = async_sleep(5)
33
34Which means your client can continue working normally, while the server
35performs the request. There are several pitfalls using :func:`async_
36<pyc.utils.helpers.async_>`, be sure to read the Notes_ section!
37
38You can test for completion using ``res.ready``, wait for completion using ``res.wait()``,
39and get the result using ``res.value``. You may set a timeout for the result using
40``res.set_expiry()``, or even register a callback function to be invoked when the
41result arrives, using ``res.add_callback()``.
42
43Notes
44^^^^^
45The returns async proxies are cached by a `weak-reference <http://docs.python.org/library/weakref.html>`_.
46Therefore, you must hold a strong reference to the returned proxy. Particularly, this means
47that instead of doing ::
48
49    res = async_(conn.root.myfunc)(1,2,3)
50
51Use ::
52
53    myfunc_async = async_(conn.root.myfunc)
54    res = myfunc_async(1,2,3)
55
56Furthermore, async requests provide **no guarantee on execution order**. In
57particular, multiple subsequent async requests may be executed in reverse
58order.
59
60
61timed()
62-------
63:class:`~rpyc.utils.helpers.timed` allows you to set a timeout for a synchronous invocation.
64When a ``timed`` function is invoked, you'll synchronously wait for the result, but no longer
65than the specified timeout. Should the invocation take longer, a
66:class:`~rpyc.core.async_.AsyncResultTimeout` will be raised.
67
68Under the hood, ``timed`` is actually implemented with ``async_``: it begins dispatches the
69operation, sets a timeout on the ``AsyncResult``, and waits for the response.
70
71Example
72^^^^^^^
73::
74
75    # allow this function to take up to 6 seconds
76    timed_sleep = rpyc.timed(conn.modules.time.sleep, 6)
77
78    # wait for 3 seconds -- works
79    async_res = timed_sleep(3)  # returns immediately
80    async_res.value             # returns after 3 seconds
81
82    # wait for 10 seconds -- fails
83    async_res = timed_sleep(10) # returns immediately
84    async_res.value             # raises AsyncResultTimeout
85
86
87Background Serving Thread
88-------------------------
89:class:`~rpyc.utils.helpers.BgServingThread` is a helper class that simply starts
90a background thread to serve incoming requests. Using it is quite simple::
91
92    bgsrv = rpyc.BgServingThread(conn)
93    # ...
94    # now you can do blocking stuff, while incoming requests are handled in the background
95    # ...
96    bgsrv.stop()
97
98Using the ``BgServingThread`` allows your code (normally the client-side) to perform blocking
99calls, while still being able to process incoming request (normally from the server). This allows
100the server to send "events" (i.e., invoke callbacks on the client side) while the client is busy
101doing other things.
102
103For a detailed example show-casing the ``BgServingThread``, see :ref:`tut5-events` in the
104tutorial.
105
106
107
108
109
110