我找到了这个 PECL 封装称为线程, ,但还没有发布。PHP 网站上什么也没有出现。

有帮助吗?

解决方案

我没有任何可用的东西。下一个最好的事情就是让一个脚本通过CLI执行另一个脚本,但这有点简陋。根据您的目标和复杂程度,这可能是也可能不是一种选择。

其他提示

来自 PHP 手册 并行线程 扩大:

pthreads 是一个面向对象的 API,允许在 PHP 中进行用户级多线程处理。它包括创建针对 Web 或控制台的多线程应用程序所需的所有工具。PHP 应用程序可以创建、读取、写入、执行并与线程、工作线程和堆栈同步。

尽管这听起来令人难以置信,但这是完全正确的。如今,PHP 可以为那些想要尝试的人提供多线程。

PHP4 的第一个版本于 2000 年 5 月 22 日发布,PHP 附带了线程安全架构 - 这是一种在多线程 SAPI(服务器 API)环境中以单独线程执行其解释器的多个实例的方法。在过去的 13 年里,该架构的设计得到了维护和改进:从那时起,它就一直在世界上最大的网站上投入使用。

用户空间中的线程从来都不是 PHP 团队关心的问题,今天仍然如此。您应该了解,在 PHP 开展业务的世界中,已经有一种定义的扩展方法 - 添加硬件。PHP 存在多年以来,硬件变得越来越便宜,因此 PHP 团队越来越不关心这一点。虽然它变得越来越便宜,但它的功能也变得更加强大。如今,我们的手机和平板电脑具有双核和四核架构以及充足的 RAM,我们的台式机和服务器通常具有 8 或 16 核、16 和 32 GB RAM,尽管我们可能并不总是能够拥有两个在预算范围内,拥有两台台式机对我们大多数人来说几乎没有什么用处。

此外,PHP 是为非程序员编写的,它是许多爱好者的母语。PHP 如此容易被采用的原因是它是一种易于学习和编写的语言。PHP 如今如此可靠的原因在于它的设计中投入了大量的工作,以及 PHP 团队做出的每一个决定。这么多年过去了,它的可靠性和纯粹的卓越性让它一直受到人们的关注。它的竞争对手已经屈服于时间或压力。

多线程编程对于大多数人来说并不容易,即使有最连贯和可靠的 API,也需要考虑不同的事情,并且有很多误解。PHP 小组不希望用户态多线程成为核心功能,它从未受到认真关注 - 确实如此。PHP 对每个人来说都不应该太复杂。

考虑到所有因素,当添加更多内容并不总是一种选择时,并且对于很多人来说,允许 PHP 利用其生产就绪和经过测试的功能来允许充分利用我们所拥有的功能仍然是有好处的任务从来都不是真正需要的。

对于那些希望探索它的人来说,pthreads 实现了一个允许用户使用多线程 PHP 应用程序的 API。它的 API 很大程度上是一项正在进行的工作,并指定了稳定性和完整性的测试级别。

众所周知,PHP 使用的一些库不是线程安全的,程序员应该清楚 pthreads 无法改变这一点,并且不要尝试尝试。但是,任何线程安全的库都是可用的,就像解释器的任何其他线程安全设置一样。

pthreads 利用 Posix 线程(即使在 Windows 中),程序员创建的是真正的执行线程,但要使这些线程有用,它们必须了解 PHP - 能够执行用户代码、共享变量并允许有用的通信方式(同步)。因此,每个线程都是使用解释器的实例创建的,但根据设计,它的解释器与解释器的所有其他实例隔离 - 就像多线程服务器 API 环境一样。pthreads 试图以一种理智且安全的方式弥补这一差距。C 线程程序员的许多担忧对于 pthreads 程序员来说并不存在,根据设计,pthreads 是读时复制和写时复制(RAM 很便宜),因此没有两个实例会操作相同的物理数据,但它们都可以影响另一个线程中的数据。PHP 可能在其核心编程中使用线程不安全功能这一事实完全无关,用户线程及其操作是完全安全的。

为什么读时复制和写时复制:

public function run() {
    ...
    (1) $this->data = $data;
    ...
    (2) $this->other = someOperation($this->data);
    ...
}

(3) echo preg_match($pattern, $replace, $thread->data);

(1) 当 pthreads 对象数据存储上持有读和写锁时,数据会从其在内存中的原始位置复制到对象存储。pthreads 不会调整变量的引用计数,如果没有进一步的引用,Zend 能够释放原始数据。

(2) someOperation 的参数引用对象存储,存储的原始数据本身是 (1) 结果的副本,为引擎再次复制到 zval 容器中,同时会持有读锁对象存储,锁被释放,引擎可以执行该函数。创建 zval 时,它的引用计数为 0,使引擎能够在操作完成后释放副本,因为不存在对其的其他引用。

(3) preg_match 的最后一个参数引用数据存储,获得读锁,将 (1) 中的数据集复制到 zval,同样引用计数为 0。锁被释放,对 preg_match 的调用对数据副本进行操作,该副本本身就是原始数据的副本。

要知道的事情:

  • 存储数据的对象存储的哈希表是线程安全的
    基于 Zend 随 PHP 提供的 TsHashTable。

  • 对象存储有一个读写锁,为 TsHashTable 提供了一个额外的访问锁,这样如果需要(确实如此,var_dump/print_r,直接访问属性,因为 PHP 引擎想要引用它们),pthreads 可以操作 TsHashTable在定义的 API 之外。

  • 仅在复制操作发生时才持有锁,当复制完成后,锁将按合理的顺序释放。

这意味着:

  • 当写作发生时,不仅读取和写入锁定,而且是附加的访问锁。表本身已锁定,其他上下文无法锁定,读取,写或影响它。

  • 当读取发生时,不仅保留了读取锁定,而且还要额外的访问锁,桌子再次被锁定。

任何两个上下文都不能物理地或同时访问对象存储中的相同数据,但在任何具有引用的上下文中进行的写入都会影响在任何具有引用的上下文中读取的数据。

这是一种无共享架构,唯一的存在方式是共存。那些有点精明的人会看到,这里有很多复制行为,他们会想知道这是否是一件好事。相当多的复制在动态运行时进行,这就是动态语言的动态。pthreads 是在对象级别实现的,因为可以获得对一个对象的良好控制,但方法(程序员执行的代码)具有另一个上下文,无需锁定和复制 - 本地方法范围。对于 pthreads 对象来说,对象范围应该被视为在上下文之间共享数据的一种方式,这就是它的目的。考虑到这一点,您可以采用技术来避免锁定对象存储,除非有必要,例如将局部作用域变量传递给线程对象中的其他方法,而不是在执行时从对象存储中复制它们。

大多数可用于 PHP 的库和扩展都是第三方的瘦包装器,PHP 核心功能在某种程度上是相同的。pthreads 不是 Posix Threads 的薄包装;它是一个基于 Posix Threads 的线程 API。在 PHP 中实现用户不理解或无法使用的线程是没有意义的。一个不了解互斥体是什么或做什么的人没有理由不能利用他们所拥有的一切,无论是在技能还是资源方面。对象的功能与对象类似,但只要两个上下文可能发生冲突,pthread 就可以提供稳定性和安全性。

任何使用过 java 的人都会看到 pthreads 对象和 java 中的线程之间的相似之处,这些人无疑会看到一个名为 ConcurrentModificationException 的错误 - 因为如果两个线程写入相同的物理数据,这听起来是 java 运行时引发的错误同时。我理解它存在的原因,但令我困惑的是,资源如此便宜,再加上运行时能够在准确且唯一的时间为用户实现安全性时检测并发性,它选择在运行时抛出可能致命的错误,而不是管理数据的执行和访问。

我相信 pthreads 不会发出这种愚蠢的错误,API 的编写是为了使线程尽可能稳定和兼容。

多线程不像使用新的数据库,应该密切注意手册中的每一个字以及 pthread 附带的示例。

最后,来自 PHP 手册:

pthreads 过去和现在都是一个取得了相当不错结果的实验​​。其任何限制或功能可能随时更改;这就是实验的本质。它的局限性——通常是由实现所施加的——存在是有充分理由的;pthreads 的目标是为 PHP 中任何级别的多任务处理提供可用的解决方案。在pthreads执行的环境中,为了提供稳定的环境,需要一些约束和限制。

以下是Wilco建议的一个例子:

$cmd = 'nohup nice -n 10 /usr/bin/php -c /path/to/php.ini -f /path/to/php/file.php action=generate var1_id=23 var2_id=35 gen_id=535 > /path/to/log/file.log & echo $!';
$pid = shell_exec($cmd);

基本上这会在命令行执行PHP脚本,但会立即返回PID,然后在后台运行。 (echo $!确保除PID之外不会返回任何其他内容。)这允许您的PHP脚本继续或退出(如果需要)。当我使用它时,我已将用户重定向到另一个页面,每隔5到60秒进行一次AJAX调用以检查报告是否仍在运行。 (我有一个表来存储gen_id及其相关的用户。)检查脚本运行以下内容:

exec('ps ' . $pid , $processState);
if (count($processState) < 2) {
     // less than 2 rows in the ps, therefore report is complete
}

这里有一篇关于这种技术的简短帖子: http://nsaunders.wordpress.com/2007/01/12/running-a-background-process-in-php/

简而言之:是的,php 中有多线程,但你应该使用多处理。

背景资料:线程对比流程

关于线程和进程的区别总是有点混乱,所以我将简短地描述两者:

  • A 线 是 CPU 将处理的命令序列。它包含的唯一数据是程序计数器。每个CPU核心一次只能处理一个线程,但可以通过调度在不同线程的执行之间切换。
  • A 过程 是一组共享资源。这意味着它由一部分内存、变量、对象实例、文件句柄、互斥体、数据库连接等组成。每个进程还包含一个或多个线程。同一进程的所有线程共享其资源,因此您可以在一个线程中使用在另一个线程中创建的变量。如果这些线程是两个不同进程的一部分,那么它们无法直接访问彼此的资源。在这种情况下你需要 进程间通信 通过例如管道、文件、套接字...

多重处理

您可以通过使用 php 创建新进程(也包含新线程)来实现并行计算。如果您的线程不需要太多通信或同步,那么这是您的选择,因为进程是隔离的并且不能干扰彼此的工作。即使一个人摔倒了,也与其他人无关。如果您确实需要大量通信,您应该继续阅读“多线程”,或者 - 遗憾的是 - 考虑使用另一种编程语言,因为进程间通信和同步引入了很多复杂性。

在 php 中,您有两种方法来创建新进程:

让操作系统为您做这件事:您可以告诉您的操作系统创建一个新进程并在其中运行一个新的(或相同的)php 脚本。

  • 为了 操作系统 您可以使用以下内容或考虑 达里尔·海因的回答:

    $cmd = 'nice php script.php 2>&1 & echo $!';
    pclose(popen($cmd, 'r'));
    
  • 为了 视窗 你可以使用这个:

    $cmd = 'start "processname" /MIN /belownormal cmd /c "script.php 2>&1"';
    pclose(popen($cmd, 'r'));
    

用叉子自己做:php 还提供了通过函数使用 fork 的可能性 pcntl_fork(). 。可以找到有关如何执行此操作的好教程 这里 但我强烈建议不要使用它,因为 fork 是反人类罪 尤其是针对oop。

多线程

通过多线程,所有线程共享其资源,因此您可以轻松地在它们之间进行通信和同步,而无需太多开销。另一方面,您必须知道自己在做什么,因为竞争条件和死锁很容易产生,但很难调试。

标准 php 不提供任何多线程,但有一个(实验性)扩展实际上提供了 - 并行线程. 。它的 api 文档甚至变成了 php.net。有了它,你可以做一些你可以做的事情 真正的编程语言 :-) 像这样:

class MyThread extends Thread {
    public function run(){
        //do something time consuming
    }
}

$t = new MyThread();
if($t->start()){
    while($t->isRunning()){
        echo ".";
        usleep(100);
    }
    $t->join();
}

为了 操作系统 有一个 安装指南 就在 stackoverflow 的这里。

为了 视窗 现在有一个:

  • 首先,您需要 php 的线程安全版本。
  • 您需要 pthreads 及其 php 扩展的预编译版本。它们可以下载 这里. 。确保您下载的版本与您的 php 版本兼容。
  • 将 php_pthreads.dll(从您刚刚下载的 zip 文件中)复制到您的 php 扩展文件夹 ([phpDirectory]/ext) 中。
  • 将 pthreadVC2.dll 复制到 [phpDirectory](根文件夹 - 不是扩展文件夹)。
  • 编辑 [phpDirectory]/php.ini 并插入以下行

    extension=php_pthreads.dll
    
  • 使用上面的脚本进行测试,并在注释所在的位置进行一些睡眠或其他操作。

现在大 :虽然这确实有效,但 php 最初并不是为多线程而设计的。存在 php 的线程安全版本,从 v5.4 开始,它似乎几乎没有错误,但在多线程环境中使用 php 仍然是 php手册中不鼓励 (但也许他们只是还没有更新这方面的手册)。一个更大的问题可能是很多常见的 扩展不是线程安全的. 。因此,您可能会获得带有此 php 扩展的线程,但您所依赖的函数仍然不是线程安全的,因此您可能会在不是您自己编写的代码中遇到竞争条件、死锁等......

您可以使用 pcntl_fork()来实现与线程类似的功能。从技术上讲,它是独立的进程,因此两者之间的通信并不像线程那么简单,我相信如果apache调用PHP,它将无法工作。

如果有人关心,我已经恢复 php_threading (与线程不同,但类似)并且我实际上已经达到了它的工作(有点)!

项目页面

下载(适用于Windows PHP 5.3 VC9 TS)

示例

自述文件

pcntl_fork()是您要搜索的内容,但它的过程不分线。 所以你会遇到数据交换的问题。要解决这些问题,您可以使用phps信号量函数( http://www.php。 net / manual / de / ref.sem.php )消息队列在开始时可能比共享内存段更容易。

无论如何,我正在开发的一个Web框架中使用的策略可以并行加载网页的资源密集型块(可能包含外部请求): 我正在做一个工作队列,知道我在等什么数据然后我为每个进程分叉工作。完成后,他们将数据存储在父进程可以访问的唯一键下的apc缓存中。一旦每个数据都存在,它就会继续。 我正在使用简单的 usleep()来等待,因为在apache中不可能进行进程间通信(孩子们将失去与父母的连接并成为僵尸......)。 所以这让我最后一件事: 自杀每个孩子都很重要! 还有一些类可以分叉进程但保留数据,我没有检查它们,但是zend框架有一个,而且它们通常做得慢而且可靠。 你可以在这里找到它: http://zendframework.com/manual/1.9/ EN / zendx.console.process.unix.overview.html 我认为他们使用shm段! 最后但并非最不重要的是,这个zend网站上有一个错误,例子中的小错误。

while ($process1->isRunning() && $process2->isRunning()) {
    sleep(1);
}
should of course be:
while ($process1->isRunning() || $process2->isRunning()) {
    sleep(1);
}

有一个基于PThreads开发的线程扩展,看起来很有希望在 https://github.com/ krakjoe /并行线程

只是一个更新,似乎PHP人员正在努力支持线程,现在可用。

以下是指向它的链接: http://php.net/manual/en/book.pthreads.php

我有一个PHP线程类,它已经在生产环境中运行了两年多。

编辑:现在可以作为作曲家库和我的MVC框架的一部分,Hazaar MVC。

请参阅: https://git.hazaarlabs.com/hazaar/hazaar-thread

我知道这是一个老问题,但你可以看一下 http://phpthreadlib.sourceforge.net/

双向通信,支持Win32,无需扩展。

有没有听说过techdivision的 appserver

它是用PHP编写的,用作管理多线程php应用程序的多线程的appserver。仍处于测试阶段,但非常谨慎。

有一个相当模糊,很快被弃用的功能叫做 ticks 。我唯一使用它的方法是允许脚本捕获SIGKILL(Ctrl + C)并正常关闭。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top