code: def read(self, nbytes, timeout=None):
          
          out = bytes()
          self._lock.acquire()
          try:
              if len(self._buffer) == 0:
                  if self._closed:
                      return out
                  # should we block?
                  if timeout == 0.0:
                      raise PipeTimeout()
                  # loop here in case we get woken up but a different thread has
                  # grabbed everything in the buffer.
                  while (len(self._buffer) == 0) and not self._closed:
                      then = time.time()
                      self._cv.wait(timeout)
                      if timeout is not None:
                          timeout -= time.time() - then
                          if timeout <= 0.0:
                              raise PipeTimeout()
  
              # something's in the buffer and we have the lock!
              if len(self._buffer) <= nbytes:
                  out = self._buffer_tobytes()
                  del self._buffer[:]
                  if (self._event is not None) and not self._closed:
                      self._event.clear()
              else:
                  out = self._buffer_tobytes(nbytes)
                  del self._buffer[:nbytes]
          finally:
              self._lock.release()
  
          return out
docs: Read data from the pipe.  The return value is a string representing
          the data received.  The maximum amount of data to be received at once
          is specified by ``nbytes``.  If a string of length zero is returned,
          the pipe has been closed.
  
          The optional ``timeout`` argument can be a nonnegative float expressing
          seconds, or ``None`` for no timeout.  If a float is given, a
          `.PipeTimeout` will be raised if the timeout period value has elapsed
          before any data arrives.
  
          :param int nbytes: maximum number of bytes to read
          :param float timeout:
              maximum seconds to wait (or ``None``, the default, to wait forever)
          :return: the read data, as a ``str`` or ``bytes``
  
          :raises:
              `.PipeTimeout` -- if a timeout was specified and no data was ready
              before that timeout