code: def _parallelFitTasks(est, train, eva, validation, epm, collectSubModel):
      
      modelIter = est.fitMultiple(train, epm)
  
      def singleTask():
          index, model = next(modelIter)
          metric = eva.evaluate(model.transform(validation, epm[index]))
          return index, metric, model if collectSubModel else None
  
      return [singleTask] * len(epm)
docs: Creates a list of callables which can be called from different threads to fit and evaluate
      an estimator in parallel. Each callable returns an `(index, metric)` pair.
  
      :param est: Estimator, the estimator to be fit.
      :param train: DataFrame, training data set, used for fitting.
      :param eva: Evaluator, used to compute `metric`
      :param validation: DataFrame, validation data set, used for evaluation.
      :param epm: Sequence of ParamMap, params maps to be used during fitting & evaluation.
      :param collectSubModel: Whether to collect sub model.
      :return: (int, float, subModel), an index into `epm` and the associated metric value.