class_docstr: Producer/Consumer implementation to (possibly) parallelize execution.
  
  It is an iterable providing a multi-threaded producer/consumer implementation,
  where there could be multiple consumers for items produced by a producer.  Since
  in DataLad majority of time is done in IO interactions with outside git and git-annex
  processes, and since we typically operate across multiple datasets, multi-threading
  across datasets operations already provides a significant performance benefit.
  
  All results from consumers are all yielded as soon as they are produced by consumers.
  Because this implementation is based on threads, `producer` and `consumer` could
  be some "closures" within code, thus having lean interface and accessing
  data from shared "outer scope".
  
  Notes
  -----
  - with jobs > 1, results are yielded as soon as available, so order
    might not match the one provided by "producer".
  - jobs > 1, is "effective" only for Python >= 3.8.  For older versions it
    would log a warning (upon initial encounter) if jobs > 1 is specified.
  - `producer` must produce unique entries. AssertionError might be raised if
    the same entry is to be consumed.
  - `consumer` can add to the queue of items produced by producer via
    `.add_to_producer_queue`. This allows for continuous reuse of the same
    instance in recursive operations (see `get` use of ProducerConsumer).
  - if producer or consumer raise an exception, we will try to "fail gracefully",
    unless subsequent Ctrl-C is pressed, we will let already running jobs to
    finish first.
  
  Examples
  --------
  A simple and somewhat boring example could be to count lines in '*.py'
  files in parallel
  
      from glob import glob
      from pprint import pprint
      from datalad.support.parallel import ProducerConsumer
  
      def count_lines(fname):
          with open(fname) as f:
              return fname, len(f.readlines())
      pprint(dict(ProducerConsumer(glob("*.py"), count_lines)))
  
  More usage examples could be found in `test_parallel.py` and around the
  codebase `addurls.py`, `get.py`, `save.py`, etc.
docstr: Removes .done from provided futures.
  
  Returns
  -------
  bool
    True if any future was removed
code: def _pop_done_futures(self, lgr):
      """Removes .done from provided futures.
  
      Returns
      -------
      bool
        True if any future was removed
      """
      done_useful = False
      # remove futures which are done
      for args, future in list(self._futures.items()):
          if future.done():
              done_useful = True
              future_ = self._futures.pop(args)
              exception = future_.exception()
              if exception:
                  lgr.debug(
                      "Future for %r raised %s.  Re-raising to trigger graceful shutdown etc",
                      args,
                      exception,
                  )
                  raise exception
              lgr.debug("Future for %r is done", args)
      return done_useful
  
imports: import concurrent.futures
  import inspect
  import sys
  import time
  import uuid
  from collections import defaultdict
  from queue import Queue, Empty
  from threading import Thread
  from .None import ansi_colors
  from ..log import log_progress
  from ..utils import path_is_subpath
  from datalad.support.exceptions import CapturedException
  import logging
label_desc: Use image node_id 12 for calling the ProducerConsumer obj's underlying member method code with example usage: obj._pop_done_futures(lgr) and returns: done_useful