
当今,异步编程需求特别是在Web开发中,在Web开发中,应用程序响应特别重要。 没有人愿意等到应用程序“下陷”,即使当时它对数据库执行查询,发送电子邮件或处理可能要花费大量时间的其他任务。 客户希望立即获得其行动的答案。 如果您的应用程序运行缓慢,则会失去客户。 面对一个悬停的应用程序,大多数情况下,用户只是简单地将其关闭而永不返回。 从用户的角度来看,该应用程序刚刚挂起,他无法理解为什么会发生这种情况:它执行的是复杂的操作还是原则上停止工作。
介绍Skyeng后端开发人员Sergey Zhuk的文章翻译。应用响应度
现代应用程序通常是响应式的,但是某些任务或操作(例如,通过网络交换数据,文件I / O或查询数据库)可能很耗时,并且会大大降低应用程序的速度。 为防止此类操作阻止应用程序,您可以在后台运行它们,从而隐藏它们引起的延迟。 同时,该应用程序保持响应,因为它可以继续执行其他任务,例如,将控制流返回到用户界面或响应其他事件。
并发与异步
人们看到异步代码时,通常会立即想到:“好极了,我可以并行化进程!”。 我可能会让您失望,但实际上并非如此。 异步和并发不是一回事。 要抓住这种差异可能很困难,所以让我们尝试找出它。
如果任务是异步执行的,则它们不会相互阻塞,并且一个任务的执行不取决于另一个任务的完成。 并发又意味着作为独立的工作单元同时启动几个单独的任务。
异步性:
去自己完成任务。 完成后让我知道,并告诉我结果。 这时,我可以继续做我的工作。
异步代码需要处理在任务执行过程中出现的依赖关系,这是使用回调实现的。 任务完成后,代码将通知另一个任务。 异步代码基本上与任务完成的时间(事件顺序)有关。

并发:
雇用任意数量的工人,并在他们之间共享任务以更快地完成任务,并在完成时通知我。 我可以继续做其他事情,或者,如果任务很紧急,我会留下来等待您返回结果。 然后,我可以汇总所有员工的最终结果。 并行执行通常需要更多资源,因此在这里它基本上取决于硬件。

为了使用实际示例理解异步执行和并行执行之间的区别,我们比较了两种流行的Web服务器:Apache和Nginx。 他们完美地说明了这种差异。 Nginx使用基于事件的异步模型,而Apache使用并行线程。 Apache为每个其他连接创建新线程,因此此处允许的最大连接数取决于系统中的可用内存量。 当达到连接限制时,Apache将停止创建其他连接。 配置Apache时的限制因素是内存(请记住,并行执行通常取决于硬件)。 如果线程停止,则客户端将等待响应,直到线程空闲并可以发送响应。
Nginx不能像Apache一样工作-它不会为每个传入请求创建新线程。 Nginx有一个主工作流程(或几个工作人员,通常对于一个处理器来说只有一个工作流程),它是单线程的。 该工作人员可以“同时”处理成千上万个连接,并在一个线程中异步执行,而不是在多个线程中并行执行。
因此,“异步”是我们构建系统的方式,它是相互独立的过程的组成。 “并行执行”是指在同一时间同时执行多个过程,尽管它们可能相关,也可能不相关。 在异步执行中,我们一次处理多个任务,在并行执行中,我们一次启动多个进程。 这似乎是同一回事,但事实并非如此。 异步描述了一种结构,并行描述了一种实现方式。
可以将异步执行与计算机上的I / O设备(鼠标,键盘,显示器)进行比较。 它们都由操作系统管理,但是每个都是内核的独立部分。 这些过程是异步的,它们可以是并行的,但这不是必需的。 因此,为了确保一致性,必须在这些独立的部分之间创建链接以进行协调。
那这个后端呢?
您可以说,响应能力在后端并不那么重要。 使用JavaScript进行的所有这些酷的异步操作都发生在一个自由端上,而您的服务器仅响应请求,因此自由端应负责应用程序的响应能力,而不是您自己。 是的,的确如此,但是服务器的任务不仅限于API响应。 有时您必须管理复杂的任务,例如下载视频。 在这种情况下,响应性可能不是关键因素,但是由于应用程序必须处于空闲状态,浪费了资源的不足。 它可以等待文件系统操作,网络交互,数据库查询等完成。 与处理器计算相比,例如,当我们转换视频文件时,这些I / O操作通常很慢。 在缓慢保存或读取文件的同时,处理器被迫处于待机状态而不是做有用的工作。 正如我们已经发现的那样,无需等待,我们可以在后台运行这些任务。 怎么了 来吧
异步PHP
在JavaScript中,提供了开箱即用的内置支持和解决方案。 还有Node.js,可让您编写异步服务器应用程序。 在JavaScript中,我们可以使用setTimeout()函数演示异步代码的示例:

运行此代码时,我们将看到以下内容:

setTimeout()函数将代码发送到队列,并在当前调用堆栈的末尾执行该代码。 这意味着我们破坏了代码的同步流并延迟了执行。 在对setTimeout()调用内的队列的调用之前,执行对console.log()的第二次调用。
那PHP呢? 在PHP中,我们没有合适的改编工具来编写真正的异步代码。 没有等效于setTimeout()的方法,我们不能简单地延迟或排队任何代码。 这就是为什么像Amp和ReactPHP这样的框架和库开始出现的原因。 他们的想法是隐藏低级语言细节,并为用户提供高级工具,使您可以编写异步代码并控制JavaScript和Node.js等进程的竞争性执行。
如果有Node.js和Go,为什么要使用PHP?
当涉及到异步PHP时,经常会出现这个问题。 由于某些原因,许多人反对使用PHP编写异步代码。 总是有人建议使用Go或Node.js,而不是PHP。
assertchris
推文完美地描述了以下情况:

当然,当刚创建PHP时,并没有使它成为可用于创建大型复杂应用程序的编程语言的目的。 当时,没有人想到过JavaScript或异步。 但是现在我们有了一个完全不同的PHP,该PHP已经具有自己的用于编写异步代码的函数(例如,stream_select()函数)。
是的,您可以使用Go或Node.js创建异步服务器应用程序,但这并不总是可以解决问题。 如果您已经具有PHP的丰富经验,那么简单地学习适合您情况的库和工具将比学习新的语言和新的生态系统容易得多。 像
ReactPHP或
Amp这样的工具允许您编写异步代码,就像在Node.js中一样。 这些工具已经相当成熟并且具有稳定的版本,因此您可以在生产中安全地使用它们。
不只是CLI
我不会写聊天,服务器或类似的东西。 我只是想加快网站速度。
通常,异步代码只能在CLI脚本中使用。 将某些异步组件集成到传统的同步环境中,甚至集成到传统的Web应用程序中,都是绝对正常的。 例如,您可以接收一个请求,然后异步调用多个不同的资源,当这些调用完成后,您可以继续请求-响应的生命周期,结果,该页面将显示得更快。
或者您需要进行一些外部API调用-例如,当用户完成付款时,您想发送电子邮件或推送通知。 您可以异步进行这些API调用,然后继续传统的同步代码流。 无需完全重写应用程序并删除所有速度变慢的东西。 只需确定会影响性能的瓶颈,就可以使用异步代码解决这些瓶颈。
是的,在大多数情况下,CLI脚本中仍使用异步代码,但它不仅限于实时聊天和服务器。 如果您只是想加快站点速度,则无需放弃Symfony或Laravel框架并创建自己的完全异步的应用程序服务器。
结论
不要害怕学习新的范例。 PHP不仅仅是“运行脚本,执行代码并消亡”。 当您意识到可以以全新的方式使用熟悉的PHP时,您会感到惊讶,就像您从未使用过它一样! 异步代码和面向事件的编程将扩展您对PHP的理解以及使用这种语言的可能性。 您无需为了编写异步应用程序而学习新的语言,仅因为“ PHP是不合适的工具”或“我一直都这样做,所以无法对其进行改进”。 试一试!
好吧,我们还提醒您,我们总是有很多
有趣的空缺供开发人员使用!