-
Notifications
You must be signed in to change notification settings - Fork 83
feature_async
If you have a slow network, your data structures are quite big, or you have to do a lot of computation or I/O in your pyro server object, then your clients spend quite a while waiting for results when calling Pyro remote methods. You could accept or even ignore this and write the code as if you were just doing normal local calls. Or, perhaps you don't want to wait until the slow remote calls have finished, ant want to continue doing other things while your results are prepared for later use.
For this, Pyro provides the async methods call mechanism.
The call will be started but runs in the background, and you can retrieve the result once it is finished. In the meantime you can do your own business. It's possible to check on the asynchronous result to see if it's done yet. You can even do this for batched calls, to improve performance even more because the whole batch of results is computed remotely for you and returned later in one go.
If your remote method doesn't return anything or you're not interested in the results, you can also choose to use oneway calls. This is even more efficient because your client doesn't even have to wait for the results to come back. However, this is something you usually configure in your server (you have to mark methods as being oneway), while the async method calls is purely a client side thing.
Finally:
-
async here is something else entirely as asynchronous (or non-blocking) I/O and Python's
asyncio
module. Don't confuse it with those. In the context here it simply means that the remote call is running in the background (using a simple worker thread) and that you can grab the result of it later on. - Pyro utilizes its
Futures
to implement this, which is discussed elsewhere.
Relevant references:
import time
import Pyro4
Pyro4.config.REQUIRE_EXPOSE = True
@Pyro4.expose
class Thingy(object):
def slow_operation(self, a, b):
print("adding {0} to {1} after a delay".format(a, b))
time.sleep(4) # pretend this is a long computation
return a+b
def operation(self, a, b):
print("adding {0} to {1} after a very slight delay".format(a, b))
time.sleep(0.5)
return a+b
if __name__ == "__main__":
Pyro4.Daemon.serveSimple({
Thingy: "async.demo"
})
import time
import Pyro4
with Pyro4.Proxy("PYRONAME:async.demo") as p:
a = Pyro4.async(p)
result = a.slow_operation(2, 3)
# while the operation runs, we can do other things...
time.sleep(1)
print(result.ready) # check if result is ready
print(result.wait(1)) # wait max 1 sec, see if it's ready now
print(result.value) # wait until result is ready and get it
def postprocess(results):
return (x*x for x in results)
def printresults(results):
print(list(results))
with Pyro4.Proxy("PYRONAME:async.demo") as p:
# queue up some calls
batch = Pyro4.batch(p)
batch.operation(2, 10)
batch.operation(3, 10)
batch.operation(4, 10)
batch.operation(5, 10)
batch.operation(6, 10)
# batch invoke
result = batch(async=True) \
.then(postprocess) \
.then(printresults)
time.sleep(4)
print("done")
Output:
<...delay...>
False
<...delay...>
False
<...delay...>
5
<...delay...>
[144, 169, 196, 225, 256]
<...delay...>
done