docs: def apply(cls, task, args, concurrent_tasks=cpu_count * 3,
                maxweight=None, weight=lambda item: 1,
                key=lambda item: 'Unspecified',
                distribute=None, progress=logging.info):
          r"""
          Apply a task to a tuple of the form (sequence, \*other_args)
          by first splitting the sequence in chunks, according to the weight
          of the elements and possibly to a key (see :func:
          `openquake.baselib.general.split_in_blocks`).
  
          :param task: a task to run in parallel
          :param args: the arguments to be passed to the task function
          :param concurrent_tasks: hint about how many tasks to generate
          :param maxweight: if not None, used to split the tasks
          :param weight: function to extract the weight of an item in arg0
          :param key: function to extract the kind of an item in arg0
          :param distribute: if not given, inferred from OQ_DISTRIBUTE
          :param progress: logging function to use (default logging.info)
          :returns: an :class:`IterResult` object
          """
          arg0 = args[0]  # this is assumed to be a sequence
          mon = args[-1]
          args = args[1:-1]
          if maxweight:  # block_splitter is lazy
              task_args = ((blk,) + args for blk in block_splitter(
                  arg0, maxweight, weight, key))
          else:  # split_in_blocks is eager
              task_args = [(blk,) + args for blk in split_in_blocks(
                  arg0, concurrent_tasks or 1, weight, key)]
          return cls(task, task_args, mon, distribute, progress).submit_all()