class_docstr: Main process (producer) produces data and stores them in a queue.
  Sub-processes (consumers) can retrieve the data-points from the queue.
  Data-points are generated via reading items from ``dataset``.
  
  :class:`DataQueue` is ephemeral. You must create a new DataQueue
  when the ``repeat`` is exhausted.
  
  See the documents of :class:`qlib.rl.utils.FiniteVectorEnv` for more background.
  
  Parameters
  ----------
  dataset
      The dataset to read data from. Must implement ``__len__`` and ``__getitem__``.
  repeat
      Iterate over the data-points for how many times. Use ``-1`` to iterate forever.
  shuffle
      If ``shuffle`` is true, the items will be read in random order.
  producer_num_workers
      Concurrent workers for data-loading.
  queue_maxsize
      Maximum items to put into queue before it jams.
  
  Examples
  --------
  >>> data_queue = DataQueue(my_dataset)
  >>> with data_queue:
  ...     ...
  
  In worker:
  
  >>> for data in data_queue:
  ...     print(data)
code: def __del__(self) -> None:
      _logger.debug(f"__del__ of {__name__}.DataQueue")
      self.cleanup()
  
imports: from __future__ import annotations
  import multiprocessing
  from multiprocessing.sharedctypes import Synchronized
  import os
  import threading
  import time
  import warnings
  from queue import Empty
  from typing import Any, Generator, Generic, Sequence, TypeVar, cast
  from qlib.log import get_module_logger
label_desc: Use image node_id 10 for calling the DataQueue obj's underlying member method code with example usage: obj.__del__() without return types