Parallel requests¶
Protocol v2 (the default) tags every request with a request_id, so replies
are matched by id instead of by arrival order. One connection can therefore have
many requests in flight at once. This page shows the two ways to use that.
When it helps¶
send_request() blocks the calling thread until the reply arrives. If you have
twenty independent reads to do, that is twenty round-trips back to back. With v2
you can send all twenty, then collect the replies as they land.
It does not help a single dependent chain (each request needs the previous reply) -- there is nothing to overlap there.
asyncio -- arequest()¶
arequest() is a coroutine. Fire several with asyncio.gather():
import asyncio
from aqpxlib import AqProtocolExerciser
async def read_all(ex: AqProtocolExerciser, messages):
return await asyncio.gather(*(ex.arequest(m) for m in messages))
with AqProtocolExerciser(host="localhost") as ex: # v2 is the default
replies = asyncio.run(read_all(ex, my_messages))
Each arequest() returns the decoded PxProtobufMsg, or raises PxAPIError if
the server answered with a non-zero status. Pass timeout=<seconds> to bound the
wait:
On timeout (or if you cancel the task) the in-flight request is abandoned on a best-effort basis: a reply that arrives later is discarded. The connection stays usable.
Threads -- async_request()¶
If you are not on an event loop, async_request() returns a plain
concurrent.futures.Future:
futures = [ex.async_request(m) for m in my_messages]
replies = [f.result(timeout=5) for f in futures]
Events fire on their own thread¶
The event monitor runs on a background thread, so a handler registered with
add_event_handler() does not run on your event loop. To touch the loop from
a handler, hop back onto it:
from aqpxlib.event import PxGpioTriggerEvent
loop = asyncio.get_running_loop()
def on_event(evt):
loop.call_soon_threadsafe(queue.put_nowait, evt)
ex.add_event_handler(PxGpioTriggerEvent, on_event)
v1¶
Passing protocol_version="v1" selects the legacy single-frame path. It has no
arequest() / async_request() -- those raise BackendError -- and one request
is in flight at a time.