title: Why does pyzmq subscriber behave differently with asyncio?
body: <p>I have an XPUB/XSUB device and a number of mock publishers running in one process. In a separate process, I want to connect a subscriber and print received message to the terminal. Below I will show two variants of a simple function to do just that. I have these functions wrapped as command-line utilities.</p>
  <p><em>My problem is that the asyncio variant never receives messages</em>.</p>
  <p>On the other hand, the non-async variant works just fine. I have tested all cases for ipc and tcp transports. The publishing process never changes in my tests, except when I restart it to change transport. The messages are short strings and published roughly once per second, so we're not looking at performance problem.</p>
  <p>The subscriber program sits indefinitely at the line <code>msg = await sock.receive_multipart()</code>. In the XPUB/XSUB device I have instrumentation that shows the forwarding of the <code>sock.setsockopt(zmq.SUBSCRIBE, channel.encode())</code> message, same as when the non-async variant connects.</p>
  <p><strong>The asyncio variant (not working, as described)</strong></p>
  <pre class="lang-py prettyprint-override"><code>def subs(url, channel):
      import asyncio
  
      import zmq
      import zmq.asyncio
  
      ctx = zmq.asyncio.Context.instance()
      sock = ctx.socket(zmq.SUB)
      sock.connect(url)
      sock.setsockopt(zmq.SUBSCRIBE, channel.encode())
  
      async def task():
          while True:
              msg = await sock.recv_multipart()
              print(' | '.join(m.decode() for m in msg))
  
      try:
          asyncio.run(task())
      finally:
          sock.setsockopt(zmq.LINGER, 0)
          sock.close()
  </code></pre>
  <p><strong>The regular blocking variant (works fine)</strong></p>
  <pre class="lang-py prettyprint-override"><code>def subs(url, channel):
      import zmq
  
      ctx = zmq.Context.instance()
      sock = ctx.socket(zmq.SUB)
      sock.connect(url)
      sock.setsockopt(zmq.SUBSCRIBE, channel.encode())
  
      def task():
          while True:
              msg = sock.recv_multipart()
              print(' | '.join(m.decode() for m in msg))
  
      try:
          task()
      finally:
          sock.setsockopt(zmq.LINGER, 0)
          sock.close()
  </code></pre>
  <p>For this particular tool there is no need to use asyncio. However, I am experiencing this problem elsewhere in my code too, where an asynchronous recv never receives. So I'm hoping that by clearing it up in this simple case I'll understand what's going wrong in general.</p>
  <p>My versions are</p>
  <pre class="lang-py prettyprint-override"><code>import zmq
  zmq.zmq_version()  # '4.3.2'
  zmq.__version__  # '19.0.2'
  </code></pre>
  <p>I'm on MacOS 10.13.6.</p>
  <p>I'm fully out of ideas. Internet, please help!</p>