PHP 中的多线程/多任务


Multi Threading / Multi Tasking in PHP

在PHP中,我们通常进行编码而不考虑服务器的能力。现在,甚至PC也具有多个内核并处理64位数据。据我所知,PHP引擎本身已经过优化,可以利用多个内核。我们程序员如何进一步优化代码以利用多个内核。

换句话说,我想知道将教我编写代码的技术,这些代码更有可能被php引擎考虑并行处理。

我不要求任何用户定义/开源队列方法,而是以利用多核并更快地工作的方式编写相同的代码。

如果您已经在做这样的事情,请提出您的想法并分享您的经验。

我希望我们应该有办法进一步优化代码。

自 2000 年 5 月 22 日首次发布 PHP4 以来,PHP 已经有很长一段时间的线程模型了。

前端线程

在 Web 应用程序的前端创建用户线程没有任何意义;扩展非常困难。Apache Worker MPM 二进制文件和mod_php使用的每客户端线程模型并不是您真正想要用来为您的网站提供服务的东西,当然,如果您正在使用它,您不希望创建额外的线程来直接响应任何 Web 请求。

为什么前端的线程是个坏主意?

您可能经常听到开发人员说前端的线程没有意义,而没有提供这种断言的理由。当你学会以所需的方式思考系统时,问题就变得很明显了:

如果客户端脚本创建 8 个线程来直接响应 Web 请求,并且 100 个客户端同时请求该脚本,则您正在请求硬件同时执行 800 个线程。

CPU的外观和工作方式必须非常不同,才能使其成为一个好主意。

我们能做些什么呢?

进取

的解决方案很可能有一个面向公众的PHP网站,但系统的实际大脑是用语言编写的,这些语言很好地支持构建进取解决方案所需的内容,如Java,C#,C++或任何当今的语言。

你应该以同样的方式使用pthreads;通过设计其组件彼此分离的系统,仅通过设计良好的高性能(RPC)API连接,这样设计多线程体系结构固有的复杂性与面向公众的网站完全隔离,以及这样的网站所需的简单,可扩展的设置。

您现在可以 HAZ 代码

让我们从Hello World开始:

<?php
class My extends Thread {
    public function run() {
        printf("Hello World'n");
    }
}
/* create a new Thread */
$my = new My();
/* start the Thread */
$my->start();
/* do not allow PHP to manage the shutdown of your Threads */
/* if a variable goes out of scope in PHP it is destroyed */
/* joining explicitly ensures integrity of the data contained in an objects */
/* members while other contexts may be accessing them */
$my->join();
?>

无聊,但我希望你读得;)

所以在一个真实的系统中,你真的不想如此明确地创建线程,你肯定只想将任务提交给某个执行器服务,所有复杂的系统,在它们的多任务要求意义上,我见过使用这样的东西......

<?php
class My extends Threaded {
    public function run() {
        printf("Hello World from %s#%lu'n",
            __CLASS__, Thread::getCurrentThreadId());   
    }
}
/* create a Pool of four threads */
/* threads in a pool are created when required */
$pool = new Pool(4);
/* submit a few tasks to the pool */
$tasks = 100;
while ($tasks--) {
    $pool->submit(new My());
}
/* shutting down the pool is tantamount to joining all workers */
/* remember what I said about joining ? */
$pool->shutdown();
?>

我已经对复杂的事情进行了非常简短的解释,您应该努力阅读所有可能的内容:

  • https://gist.github.com/krakjoe/6437782
  • https://gist.github.com/krakjoe/9384409
  • http://php.net/pthreads

可以在这里找到许多例子:https://github.com/krakjoe/pthreads/tree/master/examples

免责声明:使用线程的服务器架构并没有真正的问题,但是当你开始创建额外的线程时,你限制了它的可扩展性和按设计执行的能力,我可以想象设计良好的架构确实有能力在前端线程,但这不是一件容易的事情。此外,当涉及到高性能 Web 目标应用程序时,线程并不是工具箱中的唯一内容;研究您的所有选择。

使用 PHP 的最常见方法是通过多进程 Web 服务器(如 Apache)运行它。这意味着即使 PHP 本身不是多核感知的,操作系统也会尽最大努力在可用 CPU 之间平衡 Web 服务器进程创建的负载。

如果你有一个独立的长时间运行的PHP程序,你在一个进程中单独运行,你必须研究线程化或将程序分解为不同的进程,以便能够利用多个CPU。哪个更好/更容易取决于您的具体情况:将任务分解为碎片的难易程度,需要多少进程间/线程通信,需要多少同步等。

虽然标准的PHP发行版本身似乎没有线程支持,但有一些扩展,如php-pthreads,允许使用本机pthreads API。

要将长时间运行的PHP程序划分为多个进程,您可以使用pcntl库或proc_*函数系列。至于IPC..同样,这取决于您的需求。

已经提供了解释,因此直接输入代码。您要求的所有内容都可以通过线程实现。

require_once( 'Thread.php' );
// test to see if threading is available
if( ! Thread::available() ) 
{
   die( 'Threads not supported' );
}
// function to be ran on separate threads
function paralel( $_limit, $_name ) 
{
    for ( $index = 0; $index < $_limit; $index++ ) 
    {
        echo 'Now running thread ' . $_name . PHP_EOL;
        sleep( 1 );
    }
}
// create 2 thread objects
$t1 = new Thread( 'paralel' );
$t2 = new Thread( 'paralel' );
// start them
$t1->start( 10, 't1' );
$t2->start( 10, 't2' );
// keep the program running until the threads finish
while( $t1->isAlive() && $t2->isAlive() ) 
{
}

请记住,PHP 本身不支持线程。更详细的信息可以在这里找到 http://blog.motane.lu/2009/01/02/multithreading-in-php/

你也可以按照这个答案,当涉及到PHP和线程时,它通过代码示例更好地解释了一些。

我个人不会使用 PHP 线程,因为线程主要用于通过将进程拆分为不同的线程来加速进程,如果您的网站流量很高,那么操作系统本身将管理不同内核上的进程 CPU 上。所以,我认为你不应该担心PHP线程,也许这就是PHP团队不关注它的原因(这只是我的想法)。

PHP 在设计时并没有真正考虑多线程(它是围绕短生命周期的请求/响应模型构建的)。 不过,有几个选择。

PCNTL 扩展:生成和管理子进程。这不是多线程,因为每个子进程都是一个新的 PHP 实例。 因此,这是相当耗费资源的。 在 Windows 中不可用。

PThreads 扩展:允许生成和管理 PHP 脚本中的线程。它(据我从文档中可以看出)在 Windows 上可用,理论上线程至少应该比生成过程轻量级一些,但使用它有很多注意事项。 例如,必须编译 PHP 以确保线程安全,这可能会对非线程代码的性能产生不利影响,并可能阻止使用不支持线程安全的扩展。

ReactPHP:一个PHP代码库,提供诸如事件循环和非阻塞IO之类的内容。 严格来说,它并不支持线程(尽管我知道正在进行提供它们的工作),但它确实提供了许多有用的功能,应该可以减少对线程的需求。https://github.com/reactphp/react/wiki/FAQ 包括对线程支持状态的讨论。