我发现了这个称为线程的PECL包,但是还没有发布。PHP网站上没有任何内容。
我发现了这个称为线程的PECL包,但是还没有发布。PHP网站上没有任何内容。
Answers:
我知道没有可用的东西。第二个最好的办法是简单地使一个脚本通过CLI执行另一个脚本,但这有点基本。根据您尝试执行的操作以及操作的复杂程度,这可能是,也可能不是。
从PHP手册中的pthreads扩展中:
pthreads是一个面向对象的API,允许在PHP中进行用户级多线程处理。它包括创建针对Web或控制台的多线程应用程序所需的所有工具。PHP应用程序可以创建,读取,写入,执行并与线程,辅助线程和可堆栈对象同步。
听起来令人难以置信,这是完全正确的。今天,PHP可以为希望尝试的人提供多线程。
PHP 4的第一版发布于2000年5月22日,它带有线程安全体系结构-一种在多线程SAPI(Server API)环境中的单独线程中执行其解释程序的多个实例的方法。在过去的13年中,此体系结构的设计得到了维护和改进:从那时起,它已在世界上最大的网站上投入生产。
对于PHP团队来说,在用户领域内进行线程处理从来都不是一个问题,并且今天仍然如此。您应该了解,在PHP开展业务的世界中,已经有一种定义的扩展方法-添加硬件。PHP已经存在了许多年,硬件变得越来越便宜,因此这对于PHP团队来说越来越少了。虽然它越来越便宜,但它的功能也越来越强大。如今,我们的手机和平板电脑具有双核和四核架构以及大量的RAM,我们的台式机和服务器通常具有8或16核,16和32 GB的RAM,尽管我们可能并不总是能够拥有两个在预算之内并且拥有两个台式机对我们大多数人来说很少有用。
另外,PHP是为非程序员编写的,它是许多业余爱好者的母语。之所以很容易采用PHP,是因为它是一种易于学习和编写的语言。今天PHP之所以如此可靠的原因是,由于PHP的设计工作量很大,并且PHP小组做出了每个决定。这些年来,它的可靠性和绝对的优势使其备受关注。它的竞争对手已经陷入时间或压力。
对于大多数人来说,多线程编程并不容易,即使使用最一致,最可靠的API,也要考虑不同的事情,并且会产生许多误解。PHP小组不希望用户登陆多线程成为核心功能,因此从来没有给予过认真的关注-的确如此。PHP对每个人来说都不应该很复杂。
考虑到所有因素,允许PHP利用其生产准备就绪和经过测试的功能仍然有好处,这可以使我们充分利用现有的功能,而添加更多的功能并不总是一种选择,并且在很多方面从未真正需要任何任务。
对于希望探索它的人来说,pthreads实现了一个API,该API确实允许用户对PHP应用程序进行多线程处理。它的API尚在开发中,并指定了beta级别的稳定性和完整性。
众所周知,PHP使用的某些库不是线程安全的,程序员应该清楚pthreads不能更改它,也不会尝试尝试。但是,可以使用任何线程安全的库,就像在解释程序的任何其他线程安全设置中一样。
pthreads利用Posix线程(即使在Windows中也是如此),程序员创建的是真正的执行线程,但是对于那些有用的线程,他们必须了解PHP-能够执行用户代码,共享变量并允许有用的通信方式(同步)。因此,每个线程都是使用解释器的实例创建的,但是根据设计,它的解释器与解释器的所有其他实例是隔离的-就像多线程Server API环境一样。pthreads尝试以理智而安全的方式弥合差距。p线程的程序员并没有解决C语言中的线程程序员的许多问题,根据设计,pthreads是读取时复制和写入时复制(RAM便宜),因此,没有两个实例可以操纵相同的物理数据,但它们都可能影响另一个线程中的数据。
为什么要在读取时复制并在写入时复制:
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时,其refcount为0,从而使引擎能够在操作完成后释放副本,因为不存在对其的其他引用。
(3)preg_match的最后一个参数引用数据存储,获得读取锁,将(1)中设置的数据复制到zval,引用计数再次为0。释放该锁,对preg_match的调用在数据副本,它本身就是原始数据的副本。
要知道的事情:
对象存储的哈希表在其中存储数据(线程安全)是
基于Zend随PHP附带的TsHashTable的。
对象存储区具有读写锁,为TsHashTable提供了一个附加的访问锁,以便在需要时(并且确实如此,var_dump / print_r,当PHP引擎希望引用属性时直接访问属性)pthread可以操纵TsHashTable在定义的API之外。
仅在复制操作发生时才持有锁,复制完成后才以合理的顺序释放锁。
这表示:
发生写操作时,不仅会保留读和写锁,还会保留其他访问锁。该表本身已被锁定,其他上下文无法锁定,读取,写入或影响该表。
发生读取时,不仅会保留读取锁,还会保留附加的访问锁,从而再次锁定表。
没有两个上下文可以物理地或并行地从对象存储中访问相同的数据,但是在任何带有引用的上下文中进行的写操作都会影响在带有引用的任何上下文中读取的数据。
这是没有任何共享的体系结构,并且存在的唯一途径是共存。那些精明的人会看到,这里有很多复制工作,他们会怀疑这是否是一件好事。在动态运行时中进行了大量复制,这就是动态语言的动态。pthreads是在对象级别实现的,因为可以对一个对象获得良好的控制,但是方法-程序员执行的代码-具有另一个上下文,没有锁定和复制-本地方法范围。在使用pthreads对象的情况下,对象范围应被视为在上下文之间共享数据的一种方式,这就是其目的。考虑到这一点,您可以采用一些技术来避免锁定对象存储,除非有必要,
可用于PHP的大多数库和扩展都是围绕第三方的精简包装,在某种程度上PHP的核心功能是一回事。pthreads并不是Posix Thread的薄薄包装。它是基于Posix Threads的线程API。在PHP中实现用户不理解或无法使用的线程是没有意义的。没有任何理由不了解互斥量是或不知道互斥量的人在技能和资源上都无法利用他们所拥有的一切。一个对象的功能类似于一个对象,但是只要两个上下文相互冲突,pthread就可以提供稳定性和安全性。
在Java中工作过的任何人都将看到pthreads对象与Java中的线程之间的相似之处,这些相同的人无疑会看到一个称为ConcurrentModificationException的错误-因为如果两个线程写入相同的物理数据,这听起来会由Java运行时引发错误。同时。我理解为什么会存在它,但令我感到困惑的是,资源如此之便宜,再加上运行时能够在用户唯一能够实现安全的确切时间检测并发,因此它选择了在运行时引发可能致命的错误,而不是管理执行和对数据的访问。
我相信,pthread不会发出这种愚蠢的错误,编写该API是为了使线程尽可能稳定和兼容。
多线程并不像使用新数据库那样,应密切注意手册和pthread附带的示例中的每个单词。
最后,从PHP手册中:
pthreads曾经是并且现在是一个效果很好的实验。它的任何限制或功能可能随时更改;这就是实验的本质。它的局限性-通常是由实施施加的-有充分的理由;pthreads的目的是为任何级别的PHP中的多任务提供一个有用的解决方案。在执行pthread的环境中,为了提供稳定的环境,需要一些限制和限制。
这是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中有多线程处理,但是您应该改用多处理。
关于线程和进程的区别总是有一些困惑,因此我将简要介绍两者:
您可以通过使用php创建新进程(也包含一个新线程)来实现并行计算。如果您的线程不需要太多的通信或同步,这是您的选择,因为进程是隔离的,并且不会干扰彼此的工作。即使其中一个崩溃,也与其他人无关。如果确实需要大量通信,则应该阅读“多线程”,或者-不幸的是-考虑使用另一种编程语言,因为进程间的通信和同步会带来很多麻烦。
在php中,您可以通过两种方式创建新进程:
让OS为您完成操作:您可以告诉操作系统创建一个新进程并在其中运行新的(或相同的)php脚本。
对于Linux,您可以使用以下内容或考虑Darryl Hein的回答:
$cmd = 'nice php script.php 2>&1 & echo $!';
pclose(popen($cmd, 'r'));
对于Windows,您可以使用以下命令:
$cmd = 'start "processname" /MIN /belownormal cmd /c "script.php 2>&1"';
pclose(popen($cmd, 'r'));
自己用叉子来做:php还提供了通过pcntl_fork()函数使用派生的可能性。可以在此处找到有关如何执行此操作的很好的教程,但我强烈建议不要使用它,因为fork是危害人类,尤其是危害oop 的犯罪。
使用多线程,您的所有线程都共享它们的资源,因此您可以轻松地在它们之间进行通信和同步,而不会产生大量开销。另一方面,您必须知道自己在做什么,因为竞争条件和死锁很容易产生,但很难调试。
标准php不提供任何多线程功能,但实际上有一个(实验)扩展名-pthreads。它的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();
}
对于linux,在stackoverflow的此处有一个安装指南。
对于Windows,现在有一个:
编辑[phpDirectory] /php.ini并插入以下行
extension=php_pthreads.dll
在上面的脚本中测试一下,然后睡一会儿或在注释所在的地方进行测试。
而现在的大BUT:虽然这还真管用,PHP最初不是为多线程做。存在一个php的线程安全版本,从v5.4开始,它似乎几乎没有错误,但是php手册中仍然不鼓励在多线程环境中使用php(但也许他们只是没有更新手册)这个)。更大的问题可能是许多常见的扩展不是线程安全的。因此,您可能会获得具有此php扩展名的线程,但是您所依赖的功能仍然不是线程安全的,因此您可能会遇到竞争条件,死锁等情况,而这些原因并非是您自己编写的代码...
您可以使用pcntl_fork()实现类似于线程的功能。从技术上讲,它是独立的进程,因此两者之间的通信不是那么简单,并且我相信,如果PHP由apache调用,它将无法正常工作。
pcntl_fork()
是您要搜索的内容,但是它的过程没有线程。因此您将遇到数据交换问题。要解决它们,您可以使用phps信号量函数(http://www.php.net/manual/de/ref.sem.php)开始时,消息队列可能比共享内存段要容易一些。
无论如何,我正在开发的Web框架中正在使用的一种策略是并行加载网页的资源密集型块(可能带有外部请求):我正在做一个工作队列,以了解我正在等待什么数据,然后分叉关闭每个过程的工作。完成后,它们将数据存储在父进程可以访问的唯一密钥下的apc缓存中。一旦每个数据都存在,它将继续。我使用简单的usleep()
方法等待,因为在Apache中无法进行进程间通信(孩子们将失去与父母的联系并变成僵尸……)。因此,这使我想到了最后一件事:重要的是要杀死每个孩子!还有一些派生进程但保留数据的类,我没有检查它们,但zend framework有一个,它们通常执行缓慢但可靠的代码。你可以在这里找到它:
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);
}
Activley基于PThreads开发的Threading扩展在https://github.com/krakjoe/pthreads上看起来非常有前途
只是一个更新,似乎PHP专家正在致力于支持线程,并且现在可以使用。
我有一个PHP线程类,该类已经在生产环境中完美运行了两年以上。
编辑:现在可以作为作曲家库和我的MVC框架Hazaar MVC的一部分使用。
我知道这是一个古老的问题,但是您可以查看http://phpthreadlib.sourceforge.net/
双向通信,支持Win32,不需要扩展。
有一个相当模糊的功能,即将被弃用,称为ticks。我使用过的唯一东西是允许脚本捕获SIGKILL(Ctrl + C)并正常关闭。
pcntl_fork()
从Apache调用this()是否可以工作?