如何在 PHP 应用程序中使用多线程

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/70855/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 21:22:31  来源:igfitidea点击:

How can one use multi threading in PHP applications

phpmultithreading

提问by Steve Obbayi

Is there a realistic way of implementing a multi-threaded model in PHP whether truly, or just simulating it. Some time back it was suggested that you could force the operating system to load another instance of the PHP executable and handle other simultaneous processes.

是否有一种现实的方法可以在 PHP 中实现多线程模型,无论是真实的还是只是模拟它。前段时间有人建议您可以强制操作系统加载 PHP 可执行文件的另一个实例并处理其他并发进程。

The problem with this is that when the PHP code finished executing the PHP instance remains in memory because there is no way to kill it from within PHP. So if you are simulating several threads you can imagine whats going to happen. So I am still looking for a way multi-threading can be done or simulated effectively from within PHP. Any ideas?

这样做的问题是,当 PHP 代码执行完毕后,PHP 实例仍保留在内存中,因为无法从 PHP 内部杀死它。因此,如果您正在模拟多个线程,您可以想象会发生什么。所以我仍在寻找一种可以在 PHP 中有效地完成或模拟多线程的方法。有任何想法吗?

回答by Baba

Multi-threading is possible in php

多线程在php中是可能的

Yes you can do multi-threading in PHP with pthreads

是的,您可以使用pthreads在 PHP 中进行多线程处理

From the PHP documentation:

PHP 文档

pthreads is an object-orientated API that provides all of the tools needed for multi-threading in PHP. PHP applications can create, read, write, execute and synchronize with Threads, Workers and Threaded objects.

Warning: The pthreads extension cannot be used in a web server environment. Threading in PHP should therefore remain to CLI-based applications only.

pthreads 是一个面向对象的 API,它提供了 PHP 中多线程所需的所有工具。PHP 应用程序可以创建、读取、写入、执行和同步线程、工作线程和线程对象。

警告:不能在 Web 服务器环境中使用 pthreads 扩展。因此,PHP 中的线程应仅适用于基于 CLI 的应用程序。

Simple Test

简单测试

#!/usr/bin/php
<?php
class AsyncOperation extends Thread {

    public function __construct($arg) {
        $this->arg = $arg;
    }

    public function run() {
        if ($this->arg) {
            $sleep = mt_rand(1, 10);
            printf('%s: %s  -start -sleeps %d' . "\n", date("g:i:sa"), $this->arg, $sleep);
            sleep($sleep);
            printf('%s: %s  -finish' . "\n", date("g:i:sa"), $this->arg);
        }
    }
}

// Create a array
$stack = array();

//Initiate Multiple Thread
foreach ( range("A", "D") as $i ) {
    $stack[] = new AsyncOperation($i);
}

// Start The Threads
foreach ( $stack as $t ) {
    $t->start();
}

?>

First Run

第一次运行

12:00:06pm:     A  -start -sleeps 5
12:00:06pm:     B  -start -sleeps 3
12:00:06pm:     C  -start -sleeps 10
12:00:06pm:     D  -start -sleeps 2
12:00:08pm:     D  -finish
12:00:09pm:     B  -finish
12:00:11pm:     A  -finish
12:00:16pm:     C  -finish

Second Run

第二次运行

12:01:36pm:     A  -start -sleeps 6
12:01:36pm:     B  -start -sleeps 1
12:01:36pm:     C  -start -sleeps 2
12:01:36pm:     D  -start -sleeps 1
12:01:37pm:     B  -finish
12:01:37pm:     D  -finish
12:01:38pm:     C  -finish
12:01:42pm:     A  -finish

Real World Example

真实世界示例

error_reporting(E_ALL);
class AsyncWebRequest extends Thread {
    public $url;
    public $data;

    public function __construct($url) {
        $this->url = $url;
    }

    public function run() {
        if (($url = $this->url)) {
            /*
             * If a large amount of data is being requested, you might want to
             * fsockopen and read using usleep in between reads
             */
            $this->data = file_get_contents($url);
        } else
            printf("Thread #%lu was not provided a URL\n", $this->getThreadId());
    }
}

$t = microtime(true);
$g = new AsyncWebRequest(sprintf("http://www.google.com/?q=%s", rand() * 10));
/* starting synchronization */
if ($g->start()) {
    printf("Request took %f seconds to start ", microtime(true) - $t);
    while ( $g->isRunning() ) {
        echo ".";
        usleep(100);
    }
    if ($g->join()) {
        printf(" and %f seconds to finish receiving %d bytes\n", microtime(true) - $t, strlen($g->data));
    } else
        printf(" and %f seconds to finish, request failed\n", microtime(true) - $t);
}

回答by masterb

why don't you use popen?

你为什么不使用popen

for ($i=0; $i<10; $i++) {
    // open ten processes
    for ($j=0; $j<10; $j++) {
        $pipe[$j] = popen('script2.php', 'w');
    }

    // wait for them to finish
    for ($j=0; $j<10; ++$j) {
        pclose($pipe[$j]);
    }
}

回答by Ricardo

Threading isn't available in stock PHP, but concurrent programming is possible by using HTTP requests as asynchronous calls.

线程在 PHP 中不可用,但可以通过将 HTTP 请求用作异步调用来进行并发编程。

With the curl's timeout setting set to 1 and using the same session_id for the processes you want to be associated with each other, you can communicate with session variables as in my example below. With this method you can even close your browser and the concurrent process still exists on the server.

将 curl 的超时设置设置为 1 并为要彼此关联的进程使用相同的 session_id,您可以与会话变量进行通信,如下面的示例所示。使用这种方法,您甚至可以关闭浏览器,并发进程仍然存在于服务器上。

Don't forget to verify the correct session ID like this:

不要忘记像这样验证正确的会话 ID:

http://localhost/test/verifysession.php?sessionid=[thecorrect id]

http://localhost/test/verifysession.php?sessionid=[正确的id]

startprocess.php

启动进程.php

$request = "http://localhost/test/process1.php?sessionid=".$_REQUEST["PHPSESSID"];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $request);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 1);
curl_exec($ch);
curl_close($ch);
echo $_REQUEST["PHPSESSID"];

process1.php

进程1.php

set_time_limit(0);

if ($_REQUEST["sessionid"])
   session_id($_REQUEST["sessionid"]);

function checkclose()
{
   global $_SESSION;
   if ($_SESSION["closesession"])
   {
       unset($_SESSION["closesession"]);
       die();
   }
}

while(!$close)
{
   session_start();
   $_SESSION["test"] = rand();
   checkclose();
   session_write_close();
   sleep(5);
}

verifysession.php

验证会话.php

if ($_REQUEST["sessionid"])
    session_id($_REQUEST["sessionid"]);

session_start();
var_dump($_SESSION);

closeprocess.php

关闭进程.php

if ($_REQUEST["sessionid"])
    session_id($_REQUEST["sessionid"]);

session_start();
$_SESSION["closesession"] = true;
var_dump($_SESSION);

回答by J.D. Fitz.Gerald

While you can't thread, you do have some degree of process control in php. The two function sets that are useful here are:

虽然您不能线程化,但您确实在 php 中有一定程度的进程控制。这里有用的两个函数集是:

Process control functions http://www.php.net/manual/en/ref.pcntl.php

过程控制功能 http://www.php.net/manual/en/ref.pcntl.php

POSIX functions http://www.php.net/manual/en/ref.posix.php

POSIX 函数 http://www.php.net/manual/en/ref.posix.php

You could fork your process with pcntl_fork - returning the PID of the child. Then you can use posix_kill to despose of that PID.

您可以使用 pcntl_fork 分叉您的进程 - 返回子进程的 PID。然后您可以使用 posix_kill 来处理该 PID。

That said, if you kill a parent process a signal should be sent to the child process telling it to die. If php itself isn't recognising this you could register a function to manage it and do a clean exit using pcntl_signal.

也就是说,如果你杀死一个父进程,应该向子进程发送一个信号,告诉它死亡。如果 php 本身不能识别这一点,您可以注册一个函数来管理它并使用 pcntl_signal 进行干净的退出。

回答by pinkal vansia

using threads is made possible by the pthreads PECL extension

pthreads PECL 扩展使使用线程成为可能

http://www.php.net/manual/en/book.pthreads.php

http://www.php.net/manual/en/book.pthreads.php

回答by JasonDavis

I know this is an old question but for people searching, there is a PECL extension written in C that gives PHP multi-threading capability now, it's located here https://github.com/krakjoe/pthreads

我知道这是一个老问题,但对于搜索的人来说,现在有一个用 C 编写的 PECL 扩展,它提供了 PHP 多线程功能,它位于这里https://github.com/krakjoe/pthreads

回答by Adam Hopkinson

You can use exec() to run a command line script (such as command line php), and if you pipe the output to a file then your script won't wait for the command to finish.

您可以使用 exec() 运行命令行脚本(例如命令行 php),如果您将输出通过管道传输到文件,那么您的脚本将不会等待命令完成。

I can't quite remember the php CLI syntax, but you'd want something like:

我不太记得 php CLI 的语法,但你想要这样的东西:

exec("/path/to/php -f '/path/to/file.php' | '/path/to/output.txt'");

I think quite a few shared hosting servers have exec() disabled by default for security reasons, but might be worth a try.

我认为出于安全原因,很多共享托管服务器默认禁用了 exec(),但可能值得一试。

回答by Pete

You could simulate threading. PHP can run background processes via popen (or proc_open). Those processes can be communicated with via stdin and stdout. Of course those processes can themselves be a php program. That is probably as close as you'll get.

你可以模拟线程。PHP 可以通过 popen(或 proc_open)运行后台进程。这些进程可以通过 stdin 和 stdout 进行通信。当然,这些进程本身可以是一个 php 程序。这可能与您会得到的一样接近。

回答by Sheldmandu

Depending on what you're trying to do you could also use curl_multi to achieve it.

根据您尝试执行的操作,您还可以使用 curl_multi 来实现它。

回答by Unsigned

I know this is way old, but you could look at http://phpthreadlib.sourceforge.net/

我知道这已经很老了,但是您可以查看http://phpthreadlib.sourceforge.net/

It supports bi-directional inter-thread communication and also has builtin protections for killing off child threads (preventing orphans).

它支持双向线程间通信,并且还具有用于终止子线程(防止孤儿)的内置保护。