def METHOD_NAME(recipe, inputGlobs, output_dir, num_procs = NUM_PROCS, start_callback=None, success_callback=None, error_callback=None, metadata_defaults={}):
    """Run a given recipe over using multiple proceses.
    Parameters
    ----------
      recipe:       The recipe to run
      inputGlobs:   A dictionary of where the keys are the input names, and each
                    entry is a list of filenames which provide the data for that
                    input.
      output_dir:   The directory to save the output in
      num_procs:    The number of worker processes to launch (defaults to the number of CPUs)
    """
    #check that we've supplied the right number of images for each named input/channel
    inputLengths = [len(v) for v in inputGlobs.values()]
    if not (min(inputLengths) == max(inputLengths)):
        raise RuntimeError('The number of entries in each input category must be equal')
    taskParams = []
    outputNames = recipe.outputs
    for i in range(inputLengths[0]):
        in_d = {k:v[i] for k, v in inputGlobs.items()}
        # FIXME - change to os.path.splitext(os.path.basename(list(in_d.values())[0]).split('?')[0])[0], otherwise file_stub = ?level=N for supertiles
        file_stub = os.path.splitext(os.path.basename(list(in_d.values())[0]))[0]
        fns = os.path.join(output_dir, file_stub)
        out_d = {k:('%s_%s'% (fns,k)) for k in  outputNames}
        cntxt = {'output_dir' : output_dir, 'file_stub': file_stub}
        taskParams.append((recipe.toYAML(), in_d, out_d, cntxt, dict(metadata_defaults)))
    last_rec = None
    if num_procs == 1:
        # map(runRec, taskParams)  # map now returns iterator, which means this never runs unless we convert to list
        #[runRec(task) for task in taskParams]  # skip the map and just make the list we need anyway
        for task in taskParams:
            in_d = task[1]
            if start_callback:
                start_callback(in_d)
            try:
                last_rec = runRec(task)
                if success_callback:
                    success_callback(in_d)
            except:
                if error_callback:
                    error_callback(in_d)
                raise
        return last_rec        
    else:
        pool = multiprocessing.Pool(num_procs)
        r = pool.map_async(runRec, taskParams, error_callback = lambda e: traceback.print_exception(e, value=e, tb=e.__traceback__))
        r.wait()
        pool.close()
        return None