docs: def _MultiStream(cls, fds):
      """Effectively streams data from multiple opened BlobImage objects.
  
      Args:
        fds: A list of opened AFF4Stream (or AFF4Stream descendants) objects.
  
      Yields:
        Tuples (chunk, fd, exception) where chunk is a binary blob of data and fd
        is an object from the fds argument.
  
        If one or more chunks are missing, exception is a MissingBlobsError object
        and chunk is None. _MultiStream does its best to skip the file entirely if
        one of its chunks is missing, but in case of very large files it's still
        possible to yield a truncated file.
      """
  
      broken_fds = set()
      missing_blobs_fd_pairs = []
      for chunk_fd_pairs in collection.Batch(
          cls._GenerateChunkIds(fds), cls.MULTI_STREAM_CHUNKS_READ_AHEAD):
        chunk_fds = list(map(operator.itemgetter(0), chunk_fd_pairs))
        results_map = data_store.BLOBS.ReadBlobs(chunk_fds)
  
        for chunk_id, fd in chunk_fd_pairs:
          if chunk_id not in results_map or results_map[chunk_id] is None:
            missing_blobs_fd_pairs.append((chunk_id, fd))
            broken_fds.add(fd)
  
        for chunk, fd in chunk_fd_pairs:
          if fd in broken_fds:
            continue
  
          yield fd, results_map[chunk], None
  
      if missing_blobs_fd_pairs:
        missing_blobs_by_fd = {}
        for chunk_id, fd in missing_blobs_fd_pairs:
          missing_blobs_by_fd.setdefault(fd, []).append(chunk_id)
  
        for fd, missing_blobs in iteritems(missing_blobs_by_fd):
          e = MissingBlobsError(
              "%d missing blobs (multi-stream)" % len(missing_blobs),
              missing_chunks=missing_blobs)
          yield fd, None, e