我看到不同的二进制PHP,像非线程或线程安全?

这是什么意思?

这些包有什么不同?


当前回答

需要的并发方法背景:

Different web servers implement different techniques for handling incoming HTTP requests in parallel. A pretty popular technique is using threads -- that is, the web server will create/dedicate a single thread for each incoming request. The Apache HTTP web server supports multiple models for handling requests, one of which (called the worker MPM) uses threads. But it supports another concurrency model called the prefork MPM which uses processes -- that is, the web server will create/dedicate a single process for each request.

还有其他完全不同的并发模型(使用异步套接字和I/O),以及将两个甚至三个模型混合在一起的模型。为了回答这个问题,我们只关注上面的两个模型,并以Apache HTTP服务器为例。

需要了解PHP如何与web服务器“集成”的背景:

PHP本身并不响应实际的HTTP请求——这是web服务器的工作。因此,我们将web服务器配置为将请求转发到PHP进行处理,然后接收结果并将其发送回用户。有多种方法可以将web服务器与PHP连接起来。对于Apache HTTP服务器,最流行的是“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 !

Speaking only of Unix-based environments, I'd say that fortunately, you only have to think of this if you are going to use PHP with Apache web server, in which case you are advised to go with the prefork MPM of Apache (which doesn't use threads, and therefore, PHP thread-safety doesn't matter) and all GNU/Linux distributions that I know of will take that decision for you when you are installing Apache + PHP through their package system, without even prompting you for a choice. If you are going to use other webservers such as nginx or lighttpd, you won't have the option to embed PHP into them anyway. You will be looking at using FastCGI or something equal which works in a different model where PHP is totally outside of the web server with multiple PHP processes used for answering requests through e.g. FastCGI. For such cases, thread-safety also doesn't matter. To see which version your website is using put a file containing <?php phpinfo(); ?> on your site and look for the Server API entry. This could say something like CGI/FastCGI or Apache 2.0 Handler.

如果您还查看PHP的命令行版本,线程安全性并不重要。

最后,如果线程安全无关紧要,那么应该使用哪个版本——线程安全的还是非线程安全的?坦率地说,我没有科学的答案!但我猜非线程安全的版本更快,并且/或bug更少,否则他们只会提供线程安全的版本,而不会费心给我们选择!

其他回答

其他答案针对的是SAPIs实现,虽然这是相关的,但这个问题询问了线程安全发行版与非线程安全发行版之间的区别。

首先,PHP被编译为一个可嵌入的库,比如libphp。* Windows上的NIX和php.dll。这个库可以嵌入到任何C/CPP应用程序中,但显然它主要用于web服务器。PHP的核心启动分为两个主要阶段:模块初始化阶段和请求初始化阶段。Module init初始化PHP核心和所有扩展,而request init初始化PHP用户空间——包括本地用户空间特性和PHP代码本身。

The PHP library is setup to where the module phase only has to be called on once, but the request phase has to be reinitialized for each HTTP request. Note that CLI links to the same library as mod_php ect, and still has to go through these phases internally even though it may not be used in the context of processing HTTP requests. Also, it's important to note that PHP isn't literally designed for processing HTTP requests - most accurately, it is designed for processing CGI events. Again, this isn't just php-cgi, but all SAPI/applications including php-fpm, mod_php, CLI and even the exceedingly rare PHP desktop application.

链接到libphp的web服务器(或者更典型的SAPIs)倾向于遵循以下四种模式之一:

为每个请求创建一个全新的PHP实例(旧的CGI模式,不常见,显然不推荐) 创建一个PHP实例,但在独立的fork子进程中(一起)执行两个初始化阶段 创建一个PHP实例,在父进程fork前执行一次模块init,然后在每个HTTP请求fork后执行单独的请求阶段

注意,在例2和例3中,子进程通常在每次请求后终止。在例2中,子进程必须在每个请求结束时终止。

第四个例子与线程实现有关

在主线程中调用模块init一次,然后在其他线程中调用请求init。

在线程的情况下,请求处理线程倾向于利用线程池,每个线程运行在一个循环中,在开始时初始化请求阶段,而不是在结束时破坏请求阶段,这比为每个请求生成一个新线程更优

Regardless of how threaded implementations utilize libphp, if the module phase is initialized in one thread and request phases are called in different threads (which is the case PHP was designed for) it requires a non-trivial amount of synchronization, not just within the PHP core, but also within all native PHP extensions. Note that this is not just a matter of a “request” at this point, but synchronization that it being called on per PHP OPCODE that relies on any form of resource within the PHP core (or any PHP extension) which exists in a different thread as PHP userspace.

This places a huge demand on synchronization within thread-safe PHP distributions, which is why PHP tends to follow a "share nothing" rule which helps minimize the impact, but there is no such thing as truly "sharing nothing" in this pattern, unless each thread contains a completely separate PHP context, where the module phase and request phase is all done within the same thread per request which is not suggested or supported. If the context built within the module init phase is in a separate thread as the request init phase there will most definitely be sharing between threads. So the best attempt is made to minimize context within the module init phase that must be shared between threads, but this is not easy and in some cases not possible.

在更复杂的扩展中尤其如此,这些扩展对如何在线程之间共享自己的上下文有自己的要求,openssl是这个例子的罪魁祸首,它有效地向外扩展到任何使用它的扩展,无论是内部的(如PHP流处理程序)还是外部的(如套接字、curl、数据库扩展等)。

线程安全与非线程安全不仅仅是PHP作为SAPI实现中的“请求处理程序”在内部如何工作的问题,而是PHP作为编程语言的嵌入式虚拟机在内部如何工作的问题。

This is all made possible by the TSRM, or the thread safe resource manager, which is well made and handles a very large amount of synchronization with little perceived overhead, but the overhead is definitely there and will grow not just based on how many requests per second that the server must handle (the deciding factor on how may threads the SAPI requires), but also by how much PHP code is used per request (or per execution). In other words, large bloated frameworks can make a real difference when it comes specifically to TSRM overhead. This isn't to speak of overall PHP performance and resource requirements within thread-safe PHP, but just the additional overhead of TSRM itself within thread-safe PHP.

因此,预编译的PHP以两种方式分发,一种是在libphp中激活TSRM(线程安全的),另一种是libphp不使用任何TSRM特性(非线程安全的),因此没有TSRM的开销。

Also note that the flag used to compile PHP with TSRM (--enable-maintainer-zts or --with-zts in later PHP versions) causes phpize to extend this outward into the compilation of extensions and how they initialize their own libraries (libssl, libzip, libcurl, etc) which will often have their own way of compiling for thread-safe vs non thread-safe implementations, i.e their own synchronization mechanisms outside of TSRM and PHP as a whole. While this not exactly PHP related, in the end will still have effect on PHP performance outside of TSRM (meaning on top of TSRM). As such, PHP extensions (and their dependents, as well as external libraries PHP or extensions link to or otherwise depend on) will often have different attributes in thead-safe PHP distributions.

根据PHP文档,

下载PHP时线程安全意味着什么?

线程安全意味着二进制可以在多线程web服务器中工作 例如Windows上的Apache 2。线程安全通过创建工作 每个线程中都有一个本地存储副本,这样数据就不会碰撞 用另一个线程。 那么我该怎么选择呢?如果您选择将PHP作为CGI二进制文件运行,那么 您不需要线程安全,因为每个线程都会调用二进制文件 请求。对于多线程web服务器,例如IIS5和IIS6,您可以使用 应该使用线程版本的PHP。

以下库不是线程安全的。不建议在多线程环境中使用它们。

SNMP (Unix) mSQL (Unix) IMAP(获得/ Unix) Sybase-CT (Linux, libc5)

对我来说,我总是选择非线程安全版本,因为我总是使用nginx,或者从命令行运行PHP。

如果您将PHP作为CGI二进制文件、命令行界面或其他只使用单个线程的环境安装,则应该使用非线程安全版本。

如果您将PHP作为Apache模块安装在工作MPM(多处理模型)或其他多个PHP线程并发运行的环境中,则应该使用线程安全版本——简单地说,任何PHP的CGI/FastCGI构建都不需要线程安全。

需要的并发方法背景:

Different web servers implement different techniques for handling incoming HTTP requests in parallel. A pretty popular technique is using threads -- that is, the web server will create/dedicate a single thread for each incoming request. The Apache HTTP web server supports multiple models for handling requests, one of which (called the worker MPM) uses threads. But it supports another concurrency model called the prefork MPM which uses processes -- that is, the web server will create/dedicate a single process for each request.

还有其他完全不同的并发模型(使用异步套接字和I/O),以及将两个甚至三个模型混合在一起的模型。为了回答这个问题,我们只关注上面的两个模型,并以Apache HTTP服务器为例。

需要了解PHP如何与web服务器“集成”的背景:

PHP本身并不响应实际的HTTP请求——这是web服务器的工作。因此,我们将web服务器配置为将请求转发到PHP进行处理,然后接收结果并将其发送回用户。有多种方法可以将web服务器与PHP连接起来。对于Apache HTTP服务器,最流行的是“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 !

Speaking only of Unix-based environments, I'd say that fortunately, you only have to think of this if you are going to use PHP with Apache web server, in which case you are advised to go with the prefork MPM of Apache (which doesn't use threads, and therefore, PHP thread-safety doesn't matter) and all GNU/Linux distributions that I know of will take that decision for you when you are installing Apache + PHP through their package system, without even prompting you for a choice. If you are going to use other webservers such as nginx or lighttpd, you won't have the option to embed PHP into them anyway. You will be looking at using FastCGI or something equal which works in a different model where PHP is totally outside of the web server with multiple PHP processes used for answering requests through e.g. FastCGI. For such cases, thread-safety also doesn't matter. To see which version your website is using put a file containing <?php phpinfo(); ?> on your site and look for the Server API entry. This could say something like CGI/FastCGI or Apache 2.0 Handler.

如果您还查看PHP的命令行版本,线程安全性并不重要。

最后,如果线程安全无关紧要,那么应该使用哪个版本——线程安全的还是非线程安全的?坦率地说,我没有科学的答案!但我猜非线程安全的版本更快,并且/或bug更少,否则他们只会提供线程安全的版本,而不会费心给我们选择!

使用带有modphp的Apache MPM prefork,因为它易于配置/安装。就性能而言,它的效率相当低。我喜欢用FastCGI/PHP-FPM来做堆栈。这样您就可以使用更快的MPM Worker。整个PHP仍然是非线程的,但是Apache提供线程服务(就像它应该做的那样)。

基本上,从下到上

Linux

Apache + MPM Worker + ModFastCGI (不是FCGI) |(或)|切诺基 |(或)|恩金克斯

Php-fpm + apc

ModFCGI不正确地支持PHP-FPM,或任何外部FastCGI应用程序。它只支持非进程管理的FastCGI脚本。PHP- fpm是PHP FastCGI进程管理器。