'Run tasks in parallel'

@_run_test_complete_on_exit
def parallel(self, *tasklist):

    pids = []
    old_log_filename = self._logger.global_filename
    for (i, task) in enumerate(tasklist):
        assert isinstance(task, (tuple, list))
        self._logger.global_filename = (old_log_filename + ('.%d' % i))
        def task_func():
            base_record_indent = self._record_indent
            proc_local = self._job_state.property_factory('_state', ('_record_indent.%d' % os.getpid()), base_record_indent, namespace='client')
            self.__class__._record_indent = proc_local
            task[0](*task[1:])
        pids.append(parallel.fork_start(self.resultdir, task_func))
    old_log_path = os.path.join(self.resultdir, old_log_filename)
    old_log = open(old_log_path, 'a')
    exceptions = []
    for (i, pid) in enumerate(pids):
        try:
            parallel.fork_waitfor(self.resultdir, pid)
        except Exception as e:
            exceptions.append(e)
        new_log_path = (old_log_path + ('.%d' % i))
        if os.path.exists(new_log_path):
            new_log = open(new_log_path)
            old_log.write(new_log.read())
            new_log.close()
            old_log.flush()
            os.remove(new_log_path)
    old_log.close()
    self._logger.global_filename = old_log_filename
    if exceptions:
        msg = ('%d    task(s)    failed    in    job.parallel' % len(exceptions))
        raise error.JobError(msg)
