Start all the tasks and return data on an iterator

def results(self):
        """Start all the tasks and return data on an iterator"""
        tt = None
        for i, tf in enumerate(self[:-1]):
            tt = self[i+1]
            q = Queue(tf.qsize)
            tf.set_out(q, tt.workers)
            tt.set_in(q, tf.workers)

        if tt is None: # we have only one pool
            tt = self[0]
        q = Queue(tt.qsize)
        err_q = Queue()
        tt.set_out(q, 1)

        for t in self:
            t.set_err(err_q)
            t._start()

        for item in iterqueue(q, tt.workers):
            yield item

        errors = list(iterqueue(err_q, sum(t.workers for t in self)))

        for t in self:
            t._join()

        if len(errors) > 0:
            task_name, ex = errors[0]
            if len(errors) == 1:
                msg = 'The task "%s" raised %s' % (task_name, repr(ex),)
            else:
                msg = '%d tasks raised an exeption. First error reported on task "%s": %s' % (len(errors), task_name, repr(ex))

            raise TaskException(msg)