Skip to content
This repository has been archived by the owner on Jun 4, 2023. It is now read-only.

feature_async

Irmen de Jong edited this page Apr 22, 2016 · 3 revisions

Async calls. (and oneway)

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 itsFutures to implement this, which is discussed elsewhere.

Relevant references:

Example code (server):

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"
    })

Example code (client):

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
Clone this wiki locally