code: def submit_async_work(self, work, workunit_parent=None, on_success=None, on_failure=None):
      
      if work is None or len(work.args_tuples) == 0:  # map_async hangs on 0-length iterables.
        if on_success:
          on_success([])
      else:
        def do_work(*args):
          self._do_work(work.func, *args, workunit_name=work.workunit_name,
                        workunit_parent=workunit_parent, on_failure=on_failure)
        return self._pool.map_async(do_work, work.args_tuples, chunksize=1, callback=on_success)
docs: Submit work to be executed in the background.
  
      :param work: The work to execute.
      :param workunit_parent: If specified, work is accounted for under this workunit.
      :param on_success: If specified, a callable taking a single argument, which will be a list
                    of return values of each invocation, in order. Called only if all work succeeded.
      :param on_failure: If specified, a callable taking a single argument, which is an exception
                    thrown in the work.
  
      :return: `multiprocessing.pool.MapResult`
  
      Don't do work in on_success: not only will it block the result handling thread, but
      that thread is not a worker and doesn't have a logging context etc. Use it just to
      submit further work to the pool.