【问题标题】:Multi Threading / Multi Tasking in PHPPHP中的多线程/多任务
【发布时间】:2012-05-29 16:29:20
【问题描述】:

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

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

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

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

我希望我们可以进一步优化代码。

【问题讨论】:

  • 可能与“stackoverflow.com/questions/6107339/…”重复。
  • @Debugger,该链接完全不同。并问了完全不同的事情。粗略一看就差不多了。
  • 这是一个非问题 IMO。 PHP 是一种极其缓慢的解释性语言,如果 CPU 是您的主要瓶颈,您将需要更改平台。您是否有需要并行处理的实际的、真实的用例,或者 CPU 是您的瓶颈?如果你这样做了,你会希望将那部分代码移动到可以编译为二进制文件的东西中(作为扩展或单独的服务)
  • @Pekka,我正在寻找一种方法来编写将来会广泛使用的代码。一种更好的方法,一种更快的执行方式,这对于每天都在发展的现实来说总是好的。
  • @Imdad 您正在担心一些不太可能对您的表现产生实际影响的事情。

标签: php optimization multiprocessing


【解决方案1】:

自 2000 年 5 月 22 日 PHP4 的第一个版本发布以来,PHP 的线程模型已经存在很长时间了。

前端线程

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

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

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

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

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

我们能做些什么呢?

企业解决方案可能有一个面向公众的 PHP 网站,但系统的实际大脑是用可以很好地支持构建企业解决方案所需的那些语言编写的,例如 Java、C#、C++ 或任何语言当天是。

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

你现在可以识别代码

让我们从 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://github.com/krakjoe/pthreads/tree/master/examples

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

【讨论】:

  • 优秀。我认为没有比这更好的答案了。唯一要问的是,我是否应该让 apache 处理线程等并且不要为任何其他线程更改我的代码?
  • 使用前端可实现的最快设置,今天是 nginx 和 fpm。在后端使用线程架构,作为系统服务编写和部署,通过一些合理的 (RPC) API 与前端通信。在这种情况下,前端和后端尽可能快,并且前端附近没有用户线程,因为后端不需要那里,因为后端完成了所有艰苦的工作并且有支持它的架构。
  • 多么好的答案。你摇滚! @JoeWatkins
【解决方案2】:

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

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

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

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

【讨论】:

  • 我知道操作系统负责多核工作。但是应该有一种编码方式,更有可能被操作系统划分到多个内核中处理
  • 所有体面的进程调度程序都试图平衡内核之间的负载。你不必做任何事情。
  • @Pekka,理论上你是对的。但根据我的经验,当您不期望 eBay 或 google 等服务器负载过重时,PHP 的性能优于其他语言。
  • @Imdad “嗯”?是的,PHP 在轻负载下会表现得更好(比在重负载下)......但是,这并不意味着它会在任意负载下“表现得比其他语言更好”。当然,“足够好”就是“足够好”,一些大型网站在 PHP 上运行...
【解决方案3】:

因为已经提供了解释,所以直接放代码。您所要求的一切都可以通过 Threads 来实现。

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_pthreads 有效吗?
  • @Rangad 我提供了另一个链接,它可能会清除所有内容。
【解决方案4】:

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

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

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

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

【讨论】:

  • 戈登!可能是我错了,但 PThreads 文档声明它只是一个完全用 PHP 编写的用于线程的 API,所以你能告诉我,即使 PHP 文档本身也说 PHP 不支持真正的线程,那么如何开发这样的API以任何方式使我们能够线程化?这个 API 是否使用了某种 CLi 或其他方式,反过来会增加系统负载?
  • “PHP 的设计并没有真正考虑到多线程”的断言是完全错误的; PHP 的线程模型由来已久。这就是 pthread 可以用来实现线程的方式,因为 Zend 非常支持它。
猜你喜欢
  • 2011-01-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-29
相关资源
最近更新 更多