在PHP中的子进程之间共享变量?

在PHP中的子进程之间共享变量?,php,multithreading,shared-memory,Php,Multithreading,Shared Memory,我确信我正在尝试的是非常简单的,但是我以前从未使用过多线程,所以我不确定从哪里开始 我正在使用创建一个多线程PHP应用程序。我想做的是让3个函数同时运行,我希望它们的返回值合并到一个数组中。因此,从逻辑上讲,我需要在所有子级之间共享某个变量,然后将结果附加到该子级,或者只在单个子级和父级之间共享三个变量,然后父级可以稍后合并结果 问题是——我不知道怎么做。首先想到的是使用,但我觉得应该有一个更简单的方法 此外,如果它有任何影响,那么派生进程的函数就是一个公共类方法。因此,我的代码如下所示: &l

我确信我正在尝试的是非常简单的,但是我以前从未使用过多线程,所以我不确定从哪里开始

我正在使用创建一个多线程PHP应用程序。我想做的是让3个函数同时运行,我希望它们的返回值合并到一个数组中。因此,从逻辑上讲,我需要在所有子级之间共享某个变量,然后将结果附加到该子级,或者只在单个子级和父级之间共享三个变量,然后父级可以稍后合并结果

问题是——我不知道怎么做。首先想到的是使用,但我觉得应该有一个更简单的方法

此外,如果它有任何影响,那么派生进程的函数就是一个公共类方法。因此,我的代码如下所示:

<?php
    class multithreaded_search {
        /* ... */
        /* Constructors and such */
        /* ... */
        public function search( $string = '' ) {
            $search_types = array( 'tag', 'substring', 'levenshtein' );
            $pids = array();
            foreach( $search_types as $type ) {
                $pid = pcntl_fork();
                $pids[$pid] = $type;
                if( $pid == 0 ) { // child process
                    /* confusion */
                    $results = call_user_func( 'multithreaded_search::'.$type.'_search', $string );
                    /* What do we do with $results ? */
                }
            }
            for( $i = 0; $i < count( $pids ); $i++ ) {
                $pid = pcntl_wait();
                /* $pids[$pid] tells me the type of search that just finished */
                /* If we need to merge results in the parent, we can do it here */
            }
            /* Now all children have exited, so the search is complete */
            return $results;
        }
        private function tag_search( $string ) {
            /* perform one type of search */
            return $results;
        }
        private function substring_search( $string ) {
            /* perform one type of search */
            return $results;
        }
        private function levenshtein_search( $string ) {
            /* perform one type of search */
            return $results;
        }
    }
?>
笔记 此解决方案使用分叉进程和通过本地(内存中)套接字传递的消息。根据您的用例和设置,这可能不是最佳解决方案。例如:

  • 如果希望在几个单独的服务器之间分割处理并将结果传递回中央服务器,则
    create\u socket\u pair
    将不起作用。在这种情况下,您需要创建一个套接字,将套接字绑定到一个地址和端口,然后调用
    socket\u listen
    等待来自子服务器的结果。此外,
    pcntl\u fork
    在多服务器环境中不起作用,因为进程空间不能在不同的机器之间共享
  • 如果您正在编写命令行应用程序并且更喜欢使用线程,那么您可以使用或使用抽象pthreads的第三方库
  • 如果您不喜欢在杂草丛中挖掘,只想进行简单的多处理,而不必担心实现细节,请查看以下库:

分叉儿童在任何地方写入时,都会获得自己的专用内存空间副本,这就是“写时拷贝”。虽然shmop确实提供了对公共内存位置的访问,但脚本中定义的实际PHP变量和其他内容不会在子级之间共享


执行<代码>$x=7不会使其他子项中的$x也变为7。每个孩子都有自己的专用$x,完全独立于其他人的副本。

只要父亲和孩子知道共享内存段的键,就可以在pcnlt\u分叉之前打开shmop\u。但是请记住,pcnlt_fork在子进程中返回0,在创建子进程失败时返回-1(检查注释/混淆/附近的代码)。父进程将在$pid中包含刚刚创建的子进程的pid

请在此处查看:

使用此类:


它利用shm函数通过setVariable方法在多个进程之间共享变量……显然,您应该使用它以某种cgi模式运行PHP,最有可能的是PHP fpm

,这是有意义的,尽管我如何允许子进程在父进程的作用域中编辑变量呢?我必须使用共享内存,还是有其他方法?你不能。PHP不提供必要的低级内存访问,这样您就可以找到父级内存的位置并直接与之对话。即使您可以通过指针或类似的方式访问父进程的内存,也不能保证父进程的内存布局与子进程的相同。您必须处理php引擎的内部内存映射,以确定变量的位置,等等。。。使用共享内存,或者在两个进程之间打开一个双向通信通道,并构建一个小api来来回发送数据。我现在已经用共享内存写了一个答案,但我喜欢双向通信通道的想法(特别是因为这对返回值没有大小限制,而您必须以字节为单位定义共享内存的大小)。如何创建?本地域套接字是最简单的。让父节点在fork之前用fsockopen为每个子节点打开一个。这样,每个子节点就可以有一个通信通道:@stevendesu。您能用@stevendesu解决这个问题吗?请共享代码。感谢您的更正。我实际上没有运行代码还没有编写(因为我还没有解决共享内存问题)因此,这会引起一些有趣的调试。我也会编辑这个问题。有没有办法在没有共享内存的情况下修改父级作用域中的变量,或者我应该使用共享内存?你能解决这个问题吗?@anonymous007这个问题是从2012年开始的,所以我没有原始代码,但我不能拼凑demonstrate@anonymous007该问题已更新为基于套接字的答案感谢您快速回复我对pthreads解决方案特别感兴趣,我在这里发布了一个问题,如果您能对我建议的一个示例进行评论并提出答案,将非常有帮助ed?@anonymous007不幸的是,虽然我了解pthreads并阅读了文档,但我从未真正使用过它。最近我的大部分工作都是用Python和JavaScript完成的。我仍然使用Laravel进行一些PHP开发,但没有多线程或复杂的功能。
<?php
/*
 * I retained the same public API as my original StackOverflow question,
 * but instead of performing actual searches I simply return static data
 */

class multithreaded_search {
    private $a, $b, $c;
    public function __construct($a, $b, $c) {
        $this->a = $a;
        $this->b = $b;
        $this->c = $c;
    }

    public function search( $string = '' ) {
        $search_types = array( 'tag', 'substring', 'levenshtein' );
        $pids = array();
        $threads = array();
        $sockets = array();
        foreach( $search_types as $type ) {
            /* Create a socket to write to later */
            $sockets[$type] = array();
            socket_create_pair(AF_UNIX, SOCK_STREAM, 0, $sockets[$type]);
            $pid = pcntl_fork();
            $pids[] = $pid;
            $threads[$pid] = $type;
            if( $pid == 0 ) { // child process
                /* no more confusion */
                $results = call_user_func( 'multithreaded_search::'.$type.'_search', $string );
                /* What do we do with $results ? Write them to a socket! */
                $data = serialize($results);
                socket_write($sockets[$type][0], str_pad($data, 1024), 1024);
                socket_close($sockets[$type][0]);
                exit();
            }
        }
        $results = [];
        for( $i = 0; $i < count( $pids ); $i++ ) {
            $pid = $pids[$i];
            $type = $threads[$pid];
            pcntl_waitpid($pid, $status);
            /* $threads[$pid] tells me the type of search that just finished */
            /* If we need to merge results in the parent, we can do it here */
            $one_result = unserialize(trim(socket_read($sockets[$type][1], 1024)));
            $results[] = $one_result;
            socket_close($sockets[$type][1]);
        }
        /* Now all children have exited, so the search is complete */
        return $results;
    }

    private function tag_search() {
        return $this->a;
    }

    private function substring_search() {
        return $this->b;
    }

    private function levenshtein_search() {
        return $this->c;
    }
}

$instance = new multithreaded_search(3, 5, 7);
var_dump($instance->search());