python-trio / trio

Trio – a friendly Python library for async concurrency and I/O
https://trio.readthedocs.io
Other
6.1k stars 332 forks source link

zmq support #116

Open njsmith opened 7 years ago

njsmith commented 7 years ago

Everyone seemed really excited about this in curio, and it should be pretty simple, so hey, why not.

References:

This should go into a standalone package though – triozmq, not trio.zmq.

kawing-chiu commented 6 years ago

Hi. What is the current status of this issue? It seems that ZMQSelector is not needed anymore in newer versions of pyzmq. And curio's zmq example is now quite simple. Can zmq be supported in trio through the same way?

njsmith commented 6 years ago

Getting zmq to play nicely with regular event loops is pretty non-trivial. (That's why pyzmq used to try to dodge the issue by providing a custom loop.) We can do it though, it's just not trivial. See https://github.com/python-trio/trzmq and its readme for details of what needs to happen.

The change in pyzmq.asyncio is just that they finally did the non-trivial work described in that readme.

That curio example is just wrong AFAICT, because it completely misunderstands how the zmq waiting interface works. I guess Dave never tested it under load. If send ever blocks, it will deadlock, and recv will get stuck too under some circumstances.

jiangrzh commented 5 years ago

Hi, it's any plan to support nanomsg?

njsmith commented 5 years ago

@jiangrzh I'm not very familiar with nanomsg, but will happily cheer you on if you want to get it working with Trio :-). Do you use the older nanomsg or the newer nng? Is there a Python wrapper already that you like?

jiangrzh commented 5 years ago

@njsmith Thank you for your response. I'm new to trio and nanomsg too. I think nng is better than nanomsg, but it seens python wrapper for nng is no ready for production?

goodboy commented 5 years ago

@jiangrzh we've had brief discussion over at @codypiersall's new pynng. Sounds like @gdamore is interested in easing the pains of this integration in nng itself as well :+1:

kawing-chiu commented 5 years ago

@njsmith I've read the notes on trzmq but can't say I understand it fully, since I have little knowledge on zeromq/trio internals.

As far as I understand it, the major problem is how to tame the "edge-triggered" behavior of the zmq FD. I've found a post on how to integrate zmq with the libev eventloop, not sure whether this approach is feasible for trio?

Another thing I found is that zeromq has a new poller api which is level-triggered. It is still a draft api but may become stable sometime later. And here is pyzmq's author asking about whether this new poller api can be used to integrate with other eventloops.

njsmith commented 5 years ago

@kawing-chiu Thanks for the links! I think we do know how to integrate zmq with the trio event loop. It's just a bit complicated, so it will take a bit of work for someone to wrap their head around it, write the code, test and document it, etc. I haven't had time to do that, and even if I did then I probably wouldn't have time to focus on maintaining it well. Someone who actually uses zmq themselves would probably do a better job of that :-).

AFAICT from that poller API doc, currently it's just a more efficient version of zmq_poll, which doesn't help us – we need something fundamentally different than zmq_poll. Reading the discussion in the issue you linked (https://github.com/zeromq/libzmq/issues/2941), it does sound like there's some tentative plan to change this in the future, but it doesn't sound like anyone is actually working on it currently, so... fingers crossed I guess!

codypiersall commented 5 years ago

Just to follow up to @jiangrzh, we do have support for async operations on nng sockets in pynng. It couldn't have been done without help from @njsmith, @tgoodlet, and @gdamore! (Disclaimer: I'm the creator of pynng!)

Example usage:

import pynng
import trio

async def send_and_recv(sender, receiver, message):
    await sender.asend(message)
    return await receiver.arecv()

with pynng.Pair0(listen='tcp://127.0.0.1:54321') as s1, \
        pynng.Pair0(dial='tcp://127.0.0.1:54321') as s2:
    received = trio.run(send_and_recv, s1, s2, b'hello there old pal!')
    assert received == b'hello there old pal!'

The library is still a work in progress (what libraries aren't?). It can be installed via pip.