3

Say I have a class Messenger which is responsible for sending and receiving messages. Now I have a service that sends out requests and waits for responses via it, matching each pair with an id field in the message. In asyncio I would do:

class Service:
  ...

  async def request(self, req):
    new_id = self._gen_id()
    req.id = new_id
    fu = asyncio.Future()
    self._requests[new_id] = fu
    await self._messenger.send(req)
    return await fu

  def handle_response(self, res):
    try:
      fu = self._requests.pop(res.req_id)
    except KeyError:
      return

    fu.set_result(res)

So I could send out multiple requests from different tasks, and in each task wait for the corresponding response. (And some messages may not have a corresponding response that are handled in another way.)

But how do I do this in Trio? Should I create an Event / Condition / Queue for each request and put the response in a predefined place? If yes, which is the best for this scenario? Or there is another way to do this?

lilydjwg
  • 1,424
  • 16
  • 39
  • Here's an issue on the trio bug tracker discussing the best way to handle this case and document it: https://github.com/python-trio/trio/issues/467 – Nathaniel J. Smith Mar 20 '18 at 06:13

1 Answers1

1

You could create a simple class that contains an Event and your result.

However, strictly speaking events are overkill because multiple tasks can wait on an event, which you don't need, so you should use trio.hazmat.wait_task_rescheduled. That also gives you a hook you can use to do something when the requesting task gets cancelled before receiving its reply.

http://trio.readthedocs.io/en/latest/reference-hazmat.html#low-level-blocking

Matthias Urlichs
  • 1,789
  • 14
  • 26