4

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

这是一个示例代码

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

这是教程

4

3 回答 3

14

分叉会创建一个线程吗?

当我们 fork 一个进程时,进程空间,即进程需要执行的库和代码所在的内存区域被复制,然后不同但相关的进程继续按照操作系统调度程序的意愿执行在不同的记忆区域。

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

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

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

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

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

为什么在前端线程是一个坏主意?

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

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

线程在哪里是个好主意?

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

在 Web 基础架构的上下文中,mysql 和其他数据库服务器是多线程的,实际上 Apache 可以将 PHP 部署在多线程的基础架构中,尽管我不推荐它。

当我们查看像 mysql 这样的企业应用程序实际上是如何提供极其复杂的服务时,我们可以看到它们的进程(以及因此线程)与您的 Web 应用程序的基础设施完全隔离。

这就是我们在支持它们的语言中使用线程的方式;我们设计的系统提供服务的方式是通过某种健全的 IPC 形式,我们将复杂的基础设施与应该简单的基础设施完全隔离:我们的 Web 应用程序。

PHP 真的适合线程吗?

PHP 的内存模型是不共享的:这意味着每个解释器上下文,就 PHP 操作所需的结构和内存而言,都与任何其他上下文隔离。

要使 PHP 按预期工作,这始终必须是正确的;一个不了解 PHP 工作方式的 PHP 线程实现根本无法运行。

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

Threads 真的适合我吗?

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

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

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

但是请注意,多线程软件与您的普通 PHP 应用程序根本不同,您必须考虑以前从未考虑过的事情,在开始您的第一个线程之前注意那些无关紧要的事情。

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

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

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

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

于 2014-09-14T06:45:08.100 回答
1

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

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

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

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

于 2014-09-14T00:07:20.990 回答
0

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

在一个程序中使用多个进程也可能变得非常复杂——您必须在互斥锁上同步并对相互依赖的算法进行排序。

相反,您可以编写相互调用方法的类,这使您几乎可以解决任何问题——不使用fork就无法解决的问题很可能是因为设计不当;网站不需要执行长时间运行的任务,但他们可能会排队,添加一个 crontab-entries 就是一个例子。

于 2014-09-13T23:49:01.597 回答