php pthreads中的动态任务调度?

时间:2018-05-16 03:37:23

标签: php multithreading pthreads

我是php pthreads的新手,用于多线程。我设法通过构建一个池,设置了一些工作人员,使用for循环来提交任务并使用池来收集结果来实现我的目标。

但我认为在提交到池时,任务与工作者绑定。我相信内部逻辑是让每个工人达到尽可能相同或相等的任务数量。

在实际实施中,这种逻辑可能会导致效率问题。对于给予每个任务的不同数据,可能会产生大量时间差。或者,如果工作人员需要与服务器通信以发送/获取数据,那么数据传输甚至服务器超时和重新连接也会发生很大变化,这会导致处理不同任务的进一步差异。

举一个简单的例子,将4个任务提交给有2个工作人员的池。让我们假设每个任务都需要一定的时间来处理,无论是由哪个工作人员处理它。

任务1 2 3 4

处理时间1s 7s 2s 4s

我的理解是,在php pthreads中,每个worker都会堆叠2个要收集的任务。当任务提交到池中时,池总是将它堆叠到具有较少任务的工作者。假设没有其他开销,worker#1在3秒内处理任务#1和#3,而worker#2处理11s中的任务#2和#4。因此总池执行时间为11秒。效率非常低,因为按顺序运行所有任务需要14秒。

另一个值得注意的副作用是,#1工人将等待工人#2完成8秒钟。它可能导致实际应用程序中的服务器超时在我的应用程序中,我迭代地重用同一个池。我必须关闭每次迭代的空闲工作者连接,并在移动到下一次迭代时重新建立连接。

如果可以进行动态任务调度,则工作人员#1选择任务#1,而工作人员#2选择任务#2。 1秒后,工作人员#1选择任务#3,而工作人员#2仍然处理任务#2。在另外2秒之后,工作人员#1选择任务#4,而工作人员#2仍然处理任务#2。又过了4秒,它们都完成了,池中没有其他任务,然后它们就会关闭。所以池执行时间= worker#1(1s + 2s + 4s)= worker#2(7s)= 7s。这完美的2倍加速和100%的线程效率。与此同时,任何工人都不会闲着造成潜在的问题。

上面的例子是为了演示而制作的。现实世界会复杂得多。但我碰巧有一个应用程序,最慢的工人比最快的工人长5倍,这让我很头疼。

实际上,我对OpenMP for C ++更熟悉。它提供multiple loop scheduling methods。我认为php线程中的调度方法是静态的。我希望有一种方法可以实现动态方法。

1 个答案:

答案 0 :(得分:1)

我遇到一个问题,当一个工人上的一个长期运行的任务会导致本来可以在其他工人上使用闲置任务时,将任务堆叠在那个工人上。

Pool::submit()根据其文档的行为是:

  

将任务提交给池中的下一个工作人员

对于我的用例,我扩展了Pool类:

end

任务运行器中的用法:

namespace Task\Runner;

class Pool extends \Pool
{
    public function getIdleWorker() : ?int
    {
        if (empty($this->workers)) {
            return null;
        }

        $idleWorkerIndexes = [];

        foreach ($this->workers as $i => $worker) {
            if ($worker->getStacked() == 0)
                $idleWorkerIndexes[] = $i;
        }

        if (empty($idleWorkerIndexes))
            return null;

        return $idleWorkerIndexes[mt_rand(0, count($idleWorkerIndexes)-1)];
    }
}

需要调用Pool::submit()来创建新池,直到达到您的池大小为止,然后可以使用Pool::submitTo()将任务分配给特定的工人线程。

可以轻松地调整此方法以适合您自己的调度需求。