code: def wait_for_responses(self, *msgs, **kwargs):
          
          if self.is_closed or self.is_defunct:
              raise ConnectionShutdown("Connection %s is already closed" % (self, ))
          timeout = kwargs.get('timeout')
          fail_on_error = kwargs.get('fail_on_error', True)
          waiter = ResponseWaiter(self, len(msgs), fail_on_error)
  
          # busy wait for sufficient space on the connection
          messages_sent = 0
          while True:
              needed = len(msgs) - messages_sent
              with self.lock:
                  available = min(needed, self.max_request_id - self.in_flight + 1)
                  request_ids = [self.get_request_id() for _ in range(available)]
                  self.in_flight += available
  
              for i, request_id in enumerate(request_ids):
                  self.send_msg(msgs[messages_sent + i],
                                request_id,
                                partial(waiter.got_response, index=messages_sent + i))
              messages_sent += available
  
              if messages_sent == len(msgs):
                  break
              else:
                  if timeout is not None:
                      timeout -= 0.01
                      if timeout <= 0.0:
                          raise OperationTimedOut()
                  time.sleep(0.01)
  
          try:
              return waiter.deliver(timeout)
          except OperationTimedOut:
              raise
          except Exception as exc:
              self.defunct(exc)
              raise
docs: Returns a list of (success, response) tuples.  If success
          is False, response will be an Exception.  Otherwise, response
          will be the normal query response.
  
          If fail_on_error was left as True and one of the requests
          failed, the corresponding Exception will be raised.