class_docstr: Request aggregator that accepts processing requests, groups them into batches, waits for Runtime
  to process these batches and dispatches results back to request sources. Operates as a background process.
  
  :param process_func: function to be applied to every formed batch; called by Runtime
      Note that process_func should accept only positional args (Tensors) and return a flat tuple of Tensors
  :param max_batch_size: process at most this many inputs in a batch (task contains have one or several inputs)
  :param name: pool name
  :param min_batch_size: process at least this many inputs in a batch, otherwise wait for more
  :param timeout: wait for a subsequent task for at most this many seconds
  :param pool_size: store at most this many unprocessed tasks in a queue
  :param prefetch_batches: prepare up to this many *batches* in background for faster off-loading to runtime
  :param start: if True, start automatically at the end of __init__
class_docstr_tok: ["Request","aggregator","that","accepts","processing","requests",",","groups","them","into","batches",",","waits","for","Runtime","to","process","these","batches","and","dispatches","results","back","to","request","sources",".","Operates","as","a","background","process",".",":","param","process_func",":","function","to","be","applied","to","every","formed","batch",";","called","by","Runtime","Note","that","process_func","should","accept","only","positional","args","(","Tensors",")","and","return","a","flat","tuple","of","Tensors",":","param","max_batch_size",":","process","at","most","this","many","inputs","in","a","batch","(","task","contains","have","one","or","several","inputs",")",":","param","name",":","pool","name",":","param","min_batch_size",":","process","at","least","this","many","inputs","in","a","batch",",","otherwise","wait","for","more",":","param","timeout",":","wait","for","a","subsequent","task","for","at","most","this","many","seconds",":","param","pool_size",":","store","at","most","this","many","unprocessed","tasks","in","a","queue",":","param","prefetch_batches",":","prepare","up","to","this","many","*","batches","*","in","background","for","faster","off-loading","to","runtime",":","param","start",":","if","True",",","start","automatically","at","the","end","of","__init__"]
code: def run(self, *args, **kwargs):
      torch.set_num_threads(1)
      logger.info(f"{self.name} starting, pid={os.getpid()}")
      pending_batches = (
          {}
      )  # Dict[batch uuid, List[MPFuture]] for each batch currently in runtime
  
      output_thread = threading.Thread(
          target=self._pool_output_loop,
          args=[pending_batches],
          name=f"{self.name}_output",
          daemon=True,
      )
  
      try:
          output_thread.start()
          self._pool_input_loop(pending_batches, *args, **kwargs)
      except KeyboardInterrupt:
          logger.debug("Caught KeyboardInterrupt, shutting down")
      finally:
          output_thread.join()
  
imports: import ctypes
  import multiprocessing
  import os
  import threading
  import time
  from abc import ABCMeta, abstractmethod
  from collections import namedtuple
  from concurrent.futures import Future
  from queue import Empty
  from typing import Any, Dict, Generator, List, Tuple
  import torch
  from hivemind.utils import get_logger
  from hivemind.utils.mpfuture import InvalidStateError, MPFuture
label_desc: Use image node_id 4 for calling the TaskPool obj's underlying member method code with example usage: obj.run() without return types