代码之家  ›  专栏  ›  技术社区  ›  powtac

PHP多进程模式?

  •  7
  • powtac  · 技术社区  · 15 年前

    在一个PHP过程中,存在哪种设计模式来实现某些PHP过程的执行和结果的收集?

    背景:
    我在PHP中有许多大型树(>10000个条目),必须对其进行递归检查。我想减少经过的执行时间。

    7 回复  |  直到 9 年前
        1
  •  9
  •   Emil Ivanov    15 年前

    如果您的目标是最短的时间,那么解决方案描述起来很简单,但实现起来却不那么简单。

    你需要找到一个划分工作的模式(你在这方面没有提供太多的信息)。

    然后使用一个主进程 forks 孩子们去做这项工作。通常,您使用的进程总数应介于 n 2n ,在哪里 n 是机器的核心数量。

    假设这些数据将存储在文件中,您可以考虑使用非阻塞IO来最大化吞吐量。不这样做将使您的大部分进程花费时间等待磁盘。PHP有 stream_select() 那可能对你有帮助。请注意,使用它并不容易。

    如果你决定不使用 select -增加进程的数量可能会有所帮助。


    关于 pcntl 功能:我已经用它们写了一个布道(一个有分叉、改变会话ID、运行用户等的合适的布道),它是我写的最可靠的软件之一。因为它为每一项任务生成工人,即使其中一项任务中存在bug,它也不会影响其他任务。

        2
  •  11
  •   Josh Andreas Rehm    13 年前

    从您的PHP脚本,您可以启动另一个脚本(使用 exec )进行处理。将状态更新保存在文本文件中,然后父线程可以定期读取该文本文件。

    注意:为了避免PHP等待 执行程序 'd脚本要完成,请将输出通过管道传输到文件:

    exec('/path/to/file.php | output.log');
    

    替代地 ,可以使用 PCNTL 功能。这将使用一个PHP脚本,当分叉时,该脚本可以检测它是父脚本还是子脚本,并进行相应的操作。有一些函数可以发送/接收信号,以便在父/子文件之间进行通信,或者您将子日志记录到一个文件,并从该文件读取父日志。

    pcntl_fork 手册页:

    $pid = pcntl_fork();
    if ($pid == -1) {
         die('could not fork');
    } else if ($pid) {
         // we are the parent
         pcntl_wait($status); //Protect against Zombie children
    } else {
         // we are the child
    }
    
        3
  •  4
  •   squeeks    15 年前

    这可能是考虑使用 message queue 即使你在一台机器上运行它。

        4
  •  3
  •   rtacconi    15 年前

    您可以使用更有效的数据结构,如btree。我在Java中使用过一次,但不在PHP中使用。您可以尝试此脚本: http://www.phpclasses.org/browse/file/708.html ,它是btree的一个实现。

    如果还不够,可以使用Hadoop来实现map/reduce模式,如Michael所说。我不支持PHP进程,它似乎对性能没有帮助。

    就个人而言,我将使用PHP作为客户机,并将所有内容放入Hadoop中。本教程可能有助于: http://www.lunchpauze.com/2007/10/writing-hadoop-mapreduce-program-in-php.html .

    另一个解决方案可以是使用Btree的Java实现: http://jdbm.sourceforge.net/ . JDBM是一个使用btree+数据结构的对象数据库。然后,您可以使用PHP进行搜索,方法是使用Web服务公开数据,或者直接使用Quercus访问数据。

        5
  •  2
  •   symcbean    15 年前

    这个问题似乎有点困惑。

    我想减少绝对执行时间。

    你是说经过的时间?当然,使用正确的数据结构将提高吞吐量,但是对于给定的数据结构,算法的最小阶数是绝对的,与如何实现算法无关。

    存在哪些设计模式来实现……?

    设计模式是编码 不是用于编写程序的模板,而是用于课程设计的有用工具。从一个模式开始并使代码适合它本身就是一个反模式。

    没有人能够回答这个问题而不知道更多关于您的数据及其结构的信息,但是提高效率的关键驱动因素将是您用于实现树的数据结构。如果经过的时间很重要,那么一定要考虑并行执行,但是也有必要考虑在不同的工具中执行操作-数据库对于处理大型数据集是高度优化的,但是请注意,在关系数据库中描述树的明显方法在涉及到隔离子树和行走树。

    为了回应亚当的建议,你回答说:

    我“听说”PCNTL不是一个好的解决方案。有什么经验吗?

    你在哪里听到的?当然,从CGI或mod_php调用的脚本中分叉是一个坏主意,但是从命令行中这样做并没有错。确实有一个长期运行的PHP进程的谷歌(请注意,有很多坏信息)。您所编写的代码将根据底层操作系统的不同而有所不同—您没有说明这些操作系统。

    我怀疑,通过确定需要检查树的哪些部分,并且只检查这些部分,并在更新树时触发检查,或者至少将节点标记为“脏的”,可以解决大部分性能问题。

    您可能会发现这些有用:

    http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/ http://en.wikipedia.org/wiki/Threaded_binary_tree

    C.

        6
  •  2
  •   Michiel    15 年前

    使用web或cli?

    如果你使用网络,你可以把那部分整合到 Quercus 然后可以使用Java多线程的优点。

    我不知道Quercus有多可靠。我还建议使用一种消息队列并重构代码,这样它就不需要这个范围。

    也许您可以将代码重建为一个map/reduce模式。然后可以在Hadoop中运行PHP代码,然后可以通过两台机器对处理进行集群。

    我不知道它是否有用,但我遇到了另一个项目,叫做 Gearman .它还用于集群PHP进程。如果Hadoop不是你想要的方式,我想你也可以把它和reduce脚本结合起来。

        7
  •  0
  •   powtac    9 年前

    线程

    有一个相当新的(自2012年以来)PHP扩展可用: pthreads . 它可以通过安装 PECL .

    PHP代码中的简单实现:扩展自 Thread 班级。添加一个 run() 方法和执行 start() 方法。

    <?php
    // Example from http://www.phpgangsta.de/richtige-threads-in-php-einfach-erstellen-mit-pthreads
    class AsyncOperation extends Thread
    {
        public function __construct($threadId)
        {
            $this->threadId = $threadId;
        }
    
        public function run()
        {
            printf("T %s: Sleeping 3sec\n", $this->threadId);
            sleep(3);
            printf("T %s: Hello World\n", $this->threadId);
        }
    }
    
    $start = microtime(true);
    for ($i = 1; $i <= 5; $i++) {
        $t[$i] = new AsyncOperation($i);
        $t[$i]->start();
    }
    echo microtime(true) - $start . "\n";
    echo "end\n";
    

    输出

    >php pthreads.php
    0.041301012039185
    end
    T 1: Sleeping 3sec
    T 2: Sleeping 3sec
    T 3: Sleeping 3sec
    T 4: Sleeping 3sec
    T 5: Sleeping 3sec
    T 1: Hello World
    T 2: Hello World
    T 3: Hello World
    T 4: Hello World
    T 5: Hello World