为什么在PHP中使用多线程不是一个好主意?

时间:2014-09-13 23:36:10

标签: php multithreading pcntl

我知道php没有线程。但在本教程中,他们表明通过使用主机操作系统形成能力,我们可以实现它。它还说它不会在生产代码中这样做。为什么这不是个好主意?

以下是示例代码

$processID = pcntl_fork();
if($processID) {
     echo "I'm in the parent process!";
} else {
     echo "I'm in the child process!";
}

这是tutorial

3 个答案:

答案 0 :(得分:12)

分叉是否创建了一个线程?

当我们分叉一个进程时,进程空间,也就是说进程所需的库和代码驻留的内存区域是重复的,然后不同但相关的进程继续按照操作系统调度程序在不同的内存区域。

分叉进程和线程有什么区别?

当我们创建一个Thread时,我们告诉操作系统我们想要另一个可以在与创建它的Process相同的内存区域中运行的执行单元。

不同的操作系统实际上如何实现线程和进程超出了本答案的范围,并且不重要。

为什么分叉在前端是个坏主意?

当您复制整个地址空间时,您复制了Web服务器正在运行的内存区域,这显然会对您的操作系统造成严重破坏。

为什么在前端遇到一个坏主意?

如果客户端脚本指示操作系统在直接响应Web请求时创建8个线程,并且100个客户端同时请求该脚本,那么您将指示操作系统同时执行800个线程。

CPU和操作系统需要看起来非常不同才能让它成为一个好主意!

在哪里有一个好主意?

多线程软件和功能非常强大的硬件无处不在;没有它,计算就不会是它。

在Web基础架构的环境中,mysql和其他数据库服务器是多线程的,事实上Apache可以在多线程基础架构中部署PHP,但我不推荐它。

当我们看看像mysql这样有进取心的应用程序实际上如何提供极其复杂的服务时,我们可以看到他们的进程(以及线程)与Web应用程序的基础结构完全隔离。

这就是我们如何在支持它们的语言中使用Threads;我们设计的系统提供服务的方式是通过一些理智的IPC形式,我们完全将我们复杂的基础设施与简单的网络应用程序隔离开来:

PHP真的适合线程吗?

PHP的内存模型没有任何共享:这意味着PHP需要操作的结构和内存意义上的每个解释器上下文都与任何其他上下文隔离。

这个总是必须是真的,才能使PHP按预期工作; PHP的线程实现,不知道PHP工作的方式根本无法运行。

pthreads竭尽全力确保内存模型不被破坏,每个线程确实不与任何其他线程直接共享内存

线程真的适合我吗?

首先,认真思考以下问题:

  • 真的需要线程吗?
  • 你能找到什么其他方法来实现你想要做的任何事情?

多线程软件本质上是复杂的;在我看来,复杂的东西不是避免它的借口。

但请注意,多线程软件与普通的PHP应用程序根本不同,你必须考虑以前从未考虑过的事情,注意在开始你之前没有关系的事情。第一个线程。

你不应该猜测这些是什么,你应该尽可能彻底地教育自己,甚至准备好失败,坚持不懈。

随着知识的增加,任何事物的复杂性都会降低,这就是学习的方式,这就是它开始的地方:

https://gist.github.com/krakjoe/6437782

在我看来,它继续在手册中,在pthreads分发的许多示例中,在stackoverflow搜索和问题中,并导致荣耀。

答案 1 :(得分:1)

PHP应该在服务于前端的Web服务器上运行。在典型环境中,您可以并行使用多个用户(Web客户端),充分利用CPU内核。将工作从一个线程拆分为多个线程通常在这样的环境中没有任何意义。由于系统已经加载并且线程需要额外的同步工作等。通常最好将“复杂”任务卸载到后端系统然后报告回来。通过这种方式,执行复杂事物的后端系统可以独立扩展。工作也可以排队,以便用户获得即时报告(“我们正在工作”),然后获得有关完成的报告。

使用pcntl_fork()创建进程的副本,这可能是Web服务器进程的完整副本,它将尝试通过同一网络连接与客户端通信(这也被复制),导致完全乱七八糟它还会导致先前存在的数据库连接等混乱(至少两个进程都会尝试关闭它......所以第二个会因数据库而出现混淆错误)

对于实际的线程,pthreads extension in PECL没有创建进程的副本,但共享相同的进程与PHP的内存模型混淆(假设一次一个线程中有一个请求共享没有其他任何人)有些人使用它,但卸载到其他系统通常更好

人们经常拥有的IO操作(即数据库调用)需要时间。在这种情况下,可以进行异步操作(即参见mysqli_pollmysqli_reap_query)这基本上让你在等待IO和不时检查IO时在CPU上做一些事情。

答案 2 :(得分:0)

这里没有“实现”,pcntl_fork创建了一个新的进程。 如果你创建了多个进程,你很可能会在某些时候遇到竞争条件 - PHP不是为并行执行而设计的,你会遇到各种奇怪的错误和控制问题。

在一个程序中使用多个进程也会变得非常复杂 - 您必须在互斥锁上进行同步并对依赖于彼此的算法进行顺序化。

相反,您可以编写调用彼此方法的类,这使您几乎可以解决任何问题 - 那些不使用fork而无法解决的问题很可能是因为设计错误;网站不需要执行长时间运行的任务,但它们可能会对它们进行排队,添加crontab条目就是一个例子。