code: def communicate(self, input=None, timeout=-1):
          
          if self._process is None:
              raise RuntimeError('no child process')
          if timeout == -1:
              timeout = self._timeout
          output = [[], []]
          def writer(stream, data):
              offset = 0
              while offset < len(data):
                  buf = data[offset:offset+4096]
                  stream.write(buf)
                  offset += len(buf)
              stream.close()
          def reader(stream, data):
              while True:
                  if self._encoding:
                      buf = stream.read(4096)
                  else:
                      buf = stream.read1()
                  if not buf:
                      break
                  data.append(buf)
          if self.stdin:
              fibers.spawn(writer, self.stdin, input or b'')
          if self.stdout:
              fibers.spawn(reader, self.stdout, output[0])
          if self.stderr:
              fibers.spawn(reader, self.stderr, output[1])
          self.wait(timeout)
          empty = '' if self._encoding else b''
          stdout_data = empty.join(output[0])
          stderr_data = empty.join(output[1])
          return (stdout_data, stderr_data)
docs: Communicate with the child and return its output.
  
          If *input* is provided, it is sent to the client. Concurrent with
          sending the input, the child's standard output and standard error are
          read, until the child exits.
  
          The return value is a tuple ``(stdout_data, stderr_data)`` containing
          the data read from standard output and standard error.