我看到了PHP的不同二进制文件,例如非线程或线程安全?
这是什么意思?
这几个套餐有什么区别
对我来说,我总是选择非线程安全版本,因为我总是使用nginx,或者从命令行运行PHP。
如果您将PHP安装为CGI二进制文件、命令行界面或其他仅使用单个线程的环境,则应使用非线程安全版本。
如果您将PHP作为Apache模块安装在工作MPM(多处理模型)或其他多个PHP线程并发运行的环境中,则应使用线程安全版本-简单地说,PHP的任何CGI/FastCGI构建都不需要线程安全。
不同的Web服务器实现不同的技术来并行处理传入的HTTP请求。一种非常流行的技术是使用线程——也就是说,Web服务器将为每个传入的请求创建/专用一个线程。Apache HTTP Web服务器支持多种模型来处理请求,其中一种(称为工作线程MPM)使用线程。但它支持另一种使用进程的并发模型,称为preforkMPM——也就是说,Web服务器将为每个请求创建/专用一个进程。
还有其他完全不同的并发模型(使用异步套接字和I/O),以及将两个甚至三个模型混合在一起的模型。为了回答这个问题,我们只关心上面的两个模型,并以Apache HTTP服务器为例。
PHP本身不响应实际的HTTP请求——这是Web服务器的工作。所以我们配置Web服务器将请求转发到PHP进行处理,然后接收结果并将其发送回用户。有多种方法可以将Web服务器与PHP链接起来。对于Apache HTTP Server,最流行的是“mod_php”。这个模块实际上是PHP本身,但被编译为Web服务器的模块,因此它直接加载在其中。
还有其他方法可以将PHP与Apache和其他Web服务器链接起来,但mod_php是最流行的方法,也可以回答您的问题。
您之前可能不需要了解这些细节,因为托管公司和GNU/Linux发行版为我们准备了一切。
由于使用mod_php,PHP直接加载到Apache中,如果Apache要使用其Worker MPM(即使用线程)处理并发,那么PHP必须能够在相同的多线程环境中运行-这意味着,PHP必须是线程安全的,才能与Apache正确合作!
在这一点上,你应该在想“好吧,所以如果我使用多线程Web服务器并且我要将PHP直接嵌入其中,那么我必须使用PHP的线程安全版本”。这将是正确的想法。然而,碰巧的是,PHP的线程安全备受争议。这是一个使用如果你真的知道你在做什么的基础。
如果您想知道,如果您有选择,我个人的建议是没有在多线程环境中使用PHP!
只谈基于Unix的环境,我想说的是,幸运的是,如果你要将PHP与Apache Web服务器一起使用,你只需要考虑到这一点,在这种情况下,建议你使用Apache的preforkMPM(它不使用线程,因此,PHP线程安全无关紧要),以及我所知道的所有GNU/Linux发行版,当你通过它们的包系统安装Apache+PHP时,会为你做出决定,甚至不会提示你做出选择。如果你要使用其他Web服务器,如nginx或光,你无论如何都不会选择将PHP嵌入其中。您将看到使用FastCGI或其他相等的东西,它在不同的模型中工作,其中PHP完全是Web服务器的外面,具有多个PHP进程用于通过例如FastCGI响应请求。对于这种情况下,线程安全也无关紧要。要查看您的网站使用的版本,请在您的网站上放置一个包含<?php phpinfo(); ?>的文件并查找Server API条目。这可能会说类似于CGI/FastCGI或Apache 2.0 Handler。
<?php phpinfo(); ?>
Server API
CGI/FastCGI
Apache 2.0 Handler
如果您还查看PHP的命令行版本——线程安全无关紧要。
最后,如果线程安全无关紧要,那么你应该使用哪个版本——线程安全的还是非线程安全的?坦率地说,我没有一个科学的答案!但我猜非线程安全的版本更快和/或更少的错误,否则他们会只提供线程安全的版本,而不费心给我们选择!
使用带有modphp的Apache MPM预分叉是因为它易于配置/安装。在性能方面,它相当低效。我首选的堆栈方式,FastCGI/PHP-FPM。这样你就可以使用更快的MPM Worker。整个PHP仍然是非线程的,但Apache提供线程服务(就像它应该的那样)。
所以基本上,从下往上
Linux
Apache+MPM Worker+ModFastCGI(非FCGI)|(或)|切诺基|(或)|Nginx
PHP-FPM+APC
ModFCGI不正确支持PHP-FPM或任何外部FastCGI应用程序。它只支持非进程托管的FastCGI脚本。PHP-FPM是PHP FastCGI进程管理器。
根据php文档,
线程安全意味着二进制文件可以在多线程Web服务器中工作上下文,例如Windows上的Apache 2。线程安全通过创建每个线程中的本地存储副本,这样数据就不会冲突另一个线程。那么我该怎么选择呢?如果您选择将PHP作为CGI二进制文件运行,那么您不需要线程安全,因为二进制文件在每个请求。对于多线程Web服务器,例如IIS5和IIS6,您应该使用PHP的线程版本。
线程安全意味着二进制文件可以在多线程Web服务器中工作上下文,例如Windows上的Apache 2。线程安全通过创建每个线程中的本地存储副本,这样数据就不会冲突另一个线程。
那么我该怎么选择呢?如果您选择将PHP作为CGI二进制文件运行,那么您不需要线程安全,因为二进制文件在每个请求。对于多线程Web服务器,例如IIS5和IIS6,您应该使用PHP的线程版本。
以下库不是线程安全的。不建议在多线程环境中使用它们。
其他答案涉及SAPI实现,虽然这是相关的问题,但问题是询问线程安全与非线程安全分布之间的区别。
首先,PHP被编译为一个可嵌入的库,例如在*NIX上的libphp.so和在Windows上的php.dll。这个库可以嵌入到任何C/CPP应用程序中,但显然它主要用于Web服务器。PHP的核心启动分为两个主要阶段,模块初始化阶段,然后是请求初始化阶段。模块初始化PHP核心和所有扩展,其中请求初始化PHP用户空间-本机用户空间功能以及PHP代码本身。
PHP库被设置为模块阶段只需要调用一次,但请求阶段必须为每个HTTP请求重新初始化。请注意,CLI链接到与mod_phpect相同的库,并且仍然必须在内部经历这些阶段,即使它可能不会在处理HTTP请求的上下文中使用。此外,重要的是要注意,PHP并不是真的为处理HTTP请求而设计的——更准确地说,它是为处理CGI事件而设计的。同样,这不仅仅是php-cgi,而是所有的SAPI/应用程序,包括php-fpm、mod_php、CLI,甚至是极其罕见的PHP桌面应用程序。
链接到libphp的Web服务器(或更典型的SAPI)倾向于遵循以下四种模式之一:
请注意,在示例2和3中,子进程通常在每次请求后终止。在示例2中,子进程必须在每次请求结束时终止。
第四个例子与线程实现有关
在线程的情况下,请求处理线程倾向于使用线程池,每个线程在循环中运行,在开始时初始化请求阶段,而不是在结束时破坏请求阶段,这比每个请求产生一个新线程更优化
不管线程实现如何使用libphp,如果模块阶段在一个线程中初始化,并且请求阶段在不同的线程中调用(这就是PHP的设计目的),它需要大量的同步,不仅在PHP核心内,而且在所有本机PHP扩展内。请注意,此时这不仅仅是“请求”的问题,而是根据依赖于PHP核心(或任何PHP扩展)中任何形式的资源的OPCODE调用它的同步,这些资源作为PHP用户空间存在于不同的线程中。
这对线程安全的PHP发行版中的同步提出了巨大的要求,这就是为什么PHP倾向于遵循“不共享”规则,这有助于最大限度地减少影响,但在这种模式中没有真正的“不共享”,除非每个线程包含一个完全独立的PHP上下文,其中模块阶段和请求阶段都在每个请求的同一线程内完成,这是不建议或不支持的。如果在模块初始化阶段构建的上下文与请求初始化阶段在一个单独的线程中,那么线程之间肯定会共享。因此,最好的尝试是尽量减少模块初始化阶段中必须在线程之间共享的上下文,但这并不容易,在某些情况下是不可能的。
在更复杂的扩展中尤其如此,这些扩展对如何在线程之间共享自己的上下文有自己的要求,openssl是这个例子的主要罪魁祸首,它有效地向外扩展到任何使用它的扩展,无论是内部的,如PHP流处理程序,还是外部的,如套接字、curl、数据库扩展等。
如果在这一点上不明显,线程安全与非线程安全不仅仅是PHP如何在SAPI实现中作为“请求处理程序”在内部工作的问题,而是PHP如何在内部作为编程语言的嵌入式虚拟机工作的问题。
这一切都是由TSRM或线程安全资源管理器实现的,它做得很好,处理了非常大量的同步,几乎没有感知到的开销,但开销肯定存在,并且开销的增长不仅取决于服务器必须处理的每秒请求数量(SAPI需要多少线程的决定因素),还取决于每个请求(或每次执行)使用了多少PHP代码。换句话说,大型臃肿的框架在TSRM开销方面会产生真正的影响。这并不是说线程安全PHP中的整体PHP性能和资源需求,而是TSRM本身在线程安全PHP中的额外开销。
因此,预编译的PHP以两种形式分发,一种是在TSRM在libphp中处于活动状态(线程安全)的情况下构建的,另一种是libphp不使用任何TSRM特性(非线程安全)的情况下构建的,因此没有TSRM的开销。
另请注意,用于使用TSRM编译PHP的标志(在以后的PHP版本中是--enable-维护者-zts或--with-zts)导致phpze向外扩展到扩展的编译以及它们如何初始化自己的库(libssl、libzip、libcurl等),这些库通常有自己的编译线程安全与非线程安全实现的方式,即它们自己在TSRM和整个PHP之外的同步机制。虽然这与PHP不完全相关,但最终仍然会影响TSRM之外的PHP性能(意味着在…之上 TSRM)。因此,PHP扩展(及其依赖项,以及PHP或扩展链接到或以其他方式依赖的外部库)在安全的PHP发行版中通常具有不同的属性。