docs: def recv_array(
          socket,
          flags=0,
          copy=False,
          track=False,
          poll=None,
          poll_timeout=10000
  ):
      """recv a metadata and an optional numpy array from a zmq socket
  
      Optionally provide poll object to use recv_array with timeout
  
      poll_timeout is in millis
      """
      if poll is None:
          md = socket.recv_json(flags=flags)
      else:
          # one-try "Lazy Pirate" method: http://zguide.zeromq.org/php:chapter4
          socks = dict(poll.poll(poll_timeout))
          if socks.get(socket) == zmq.POLLIN:
              reply = socket.recv_json(flags=flags)
              # note that reply can be an empty array
              md = reply
          else:
              raise NoResponseException(
                  "Recv_array got no response within timeout (1)")
  
      if md['parts'] == 0:
          # No array expected
          A = None
      elif md['parts'] == 1:
          # although the check is not strictly necessary, we try to maintain fast
          # pointer transfer when there is only 1 part
  
          if poll is None:
              msg = socket.recv(flags=flags, copy=copy, track=track)
          else:
              # one-try "Lazy Pirate" method: http://zguide.zeromq.org/php:chapter4
              socks = dict(poll.poll(poll_timeout))
              if socks.get(socket) == zmq.POLLIN:
                  reply = socket.recv(flags=flags, copy=copy, track=track)
                  # note that reply can be an empty array
                  msg = reply
              else:
                  raise NoResponseException(
                      "Recv_array got no response within timeout (2)")
          buf = buffer(msg)
          A = np.frombuffer(buf, dtype=md['dtype'])
          A = A.reshape(md['shape'])
  
          if 'fill_value' in md:
              A = np.ma.masked_equal(A, md['fill_value'])
  
      else:
          # multi part array
          A = np.zeros(np.prod(md['shape']), dtype=md['dtype'])
          arr_position = 0
          for i in range(md['parts']):
              if poll is None:
                  msg = socket.recv(flags=flags, copy=copy, track=track)
              else:
                  # one-try "Lazy Pirate" method: http://zguide.zeromq.org/php:chapter4
                  socks = dict(poll.poll(poll_timeout))
                  if socks.get(socket) == zmq.POLLIN:
                      reply = socket.recv(flags=flags, copy=copy, track=track)
                      if not reply:
                          raise EmptyResponseException(
                              "Recv_array got an empty response (2)")
                      msg = reply
                  else:
                      raise NoResponseException(
                          "Recv_array got no response within timeout (2)")
              buf = buffer(msg)
              a = np.frombuffer(buf, dtype=md['dtype'])
              A[arr_position:arr_position + a.shape[0]] = a[:]
              arr_position += a.shape[0]
          A = A.reshape(md['shape'])
  
          if 'fill_value' in md:
              A = np.ma.masked_equal(A, md['fill_value'])
  
      return A, md