def _as_completed(
    tasks: Mapping[str, Callable[[], _T]],
    *,
    timeout: float | None = None,
    max_workers: int | None = None,
) -> Iterator[tuple[str, futures.Future[_T]]]:
  """Maps a function to a sequence of values in parallel.

  IMPORTANT: Passed callables must be threadsafe.

  Args:
    tasks: callables to execute (MUST BE THREADSAFE)
    timeout: the maximum number of seconds to wait for all tasks to complete.
    max_workers: them maximum number of parallel jobs. If None will use as many
      workers as there are tasks.

  Yields:
    (key, future) as tasks complete.

  Raises:
    TimeoutError: If all the results are not generated before the timeout.
  """
  if not tasks:
    return
  if max_workers is None:
    max_workers = len(tasks)
  with _executor(max_workers=max_workers) as executor_:
    key_by_future = {
        executor_.submit(_run_task, key, task): key
        for key, task in tasks.items()
    }
    for future in futures.as_completed(key_by_future, timeout=timeout):
      yield key_by_future[future], future
Maps a function to a sequence of values in parallel.

  IMPORTANT: Passed callables must be threadsafe.

  Args:
    tasks: callables to execute (MUST BE THREADSAFE)
    timeout: the maximum number of seconds to wait for all tasks to complete.
    max_workers: them maximum number of parallel jobs. If None will use as many
      workers as there are tasks.

  Yields:
    (key, future) as tasks complete.

  Raises:
    TimeoutError: If all the results are not generated before the timeout.
  
concordia/utils/concurrency.py