设为首页 加入收藏

TOP

学习swoole之前,你需要知道的几件事(一)
2023-07-23 13:26:12 】 浏览:109
Tags:学习 swoole 之前

学习swoole需要的前置知识

学习一项新的技术,最重要的就why、what、how。

这门技术是什么,为什么用它,要怎么用它。这篇文档的作用就是为了解释what与why。

php-fpm与swoole的异同

同步与异步

cpu上下文切换
事件循环--异步是如何实现的
总结

php-fpm与swoole的异同

常驻内存

一个请求通过nginx转发到php来运行,中间是通过php-fpm来沟通连接的,通过一种叫cgi的协议来通信。

在php-fpm还未出现之前,php一般都是通过php-cgi这个php官方组件来与web server进行通信的,它的特点是每次运行都需要重新加载一次php.ini中的配置,并且每有一个请求都会重新启动一个进程来执行,执行完毕后再销毁掉。

这种方式每次都会重新解析php.ini、重新载入全部扩展,并重新初始化全部数据结构,这无疑是对cpu性能的浪费行为,于是就出现了fast cgi

fast cgi的应用体现便是php-fpm。通过一个master进程管理多个worker进程的方式,在主进程启动时便将php.ini中的配置等信息载入内存,worker进程创建时会继承master进程的数据,并且worker进程处理完一个请求后不会销毁,而是继续等待下一个请求。所以只需要一次加载,php.ini与扩展和初始化数据这部分的性能便被节省出来了。虽然php.ini的配置初始化被节省掉了,但是我们平时使用的laravel等php开发框架中同样有冗长的ioc容器初始化,依赖创建的过程,这个问题php-fpm就无能为力了。

那么说完了php-fpm,这些和swoole又有什么关系呢?相同点就在于,swoole也是常驻内存的,也是一个master管理多个worker进程,所以也节省掉了多次载入php.ini等配置的消耗。

并且,
由于swoole本身就是一个PHP扩展,它的启动是在php脚本内开始的,因此可以看做是php开发框架的一部分,那么php框架初始化的那一系列重复初始化便同样被节省掉了。
这便是swoole高性能的原因。

swoole在宣传上写的是为了解决传统php-fpm模式并发慢的问题而诞生的,那么就带来一个问题:

php-fpm模式为什么慢?

php-fpm模式是以多进程方式来运行的,一个master进程创建并管理多个work进程。master进程只负责接收请求和返回响应,剩下的运行工作交给work进程来执行。

alt php-fpm

也就是说每一个请求都对应一个work进程,同一时刻,服务器上有多少work进程,这台服务器就可以处理多少的并发。
这么一看是不是觉得php-fpm的并发能力特别差?假设不考虑服务器配置问题,默认的400个进程数同时就只能支持400的并发。
实际情况肯定没有这么差,假设很多的脚本只需要0.001秒就处理完成了,如果所有的请求都可以快速处理的话,那么我们可以说1秒钟的并发数就等于400*1000=40万的并发。

这么一看是不是觉得php-fpm的性能也没这么差了?

但是,如果你的业务数据量很大,mysql的查询效率不高,每次请求都需要花费1秒钟的时间才能返回响应的话呢?
那么每秒钟的并发数就从40W又下降回400了。

而swoole,就是为了解决这个问题所开发出来的一个php扩展,它使得每个worker进程不会因为1秒钟的io阻塞而白白让cpu浪费1秒钟的性能。

swoole的运行方式

按照刚刚的那个例子来解释的话,swoole的处理方式就是在一个worker进程开始进行mysql io查询的时候就将这个请求任务暂时挂起,立马开始执行下一个请求,然后等到第一个请求中的mysql io数据返回之后,再切换回第一个请求中继续执行代码返回响应。这样一来,对于cpu来说,它一直在执行代码,没有因为请求中mysql的1秒io耗时处于空闲状态。

那么,既然那1秒的io耗时没有对cpu产生影响,那么对于服务器来说,每一秒钟的并发数和之前一样仍然是40W,只不过由于每个请求还是有1秒的耗时,所以单个请求的响应时间依然是1秒钟,但是对于cpu来说,它每秒处理的请求数量并没有减少,因为对于cpu来说一个请求的io耗时是1秒,1000个请求的总耗时依旧是1秒。

同步与异步

什么是同步

我们平时编写的php代码就是同步代码。php解释器一行一行的编译运行我们的代码,碰到数据库查询,或者第三方接口调用,或者系统磁盘读写。这些不归php当前进程管辖的部分都是io操作,它们可能是磁盘io,可能是网络io。而同步的代码一旦碰到这些io操作,它们就会停下来等待,等待mysql返回查询结果,等待第三方接口返回响应,等待linxu文件系统返回磁盘读取结果。在等待的过程中,cpu的性能就被浪费掉了。

什么是异步

异步代码就是说代码在运行到一个需要等待的io操作时,不在原地傻等,而是继续向下执行其他代码,等到io操作有返回结果通知的时候再回过头来执行处理逻辑。

一个简单的例子就是js中的Ajax,下面这个例子当中,js把Ajax请求发送出去就开始执行下一行代码了,所以是先alert 2,然后等到Ajax响应返回再执行回调函数alert1。

$.ajax({
    url:"http://www.test.com/get_data",
    success: function (result) {
        alert(1);
    }
});

alert(2);

对于生活中的例子来说,异步就是一个人同时使用洗衣机洗衣服与使用电饭煲做饭,假设洗衣机洗一次衣服要40分钟,电饭煲煮饭也需要40分钟,那么这两件事都完成需要多长时间呢?

是的,也是40分钟(最多多出一些把衣服和米分别放进机器的可以忽略不计的时间),因为人把衣服放进洗衣机就可以去做其他事了,不会守在洗衣机旁傻等,可以去开电饭煲了。而洗衣机洗好衣服以后,会有滴滴声提示人衣服已经洗好了。

回到一开始那个swoole并发数的例子,那些需要1秒钟来查询mysql数据的请求,它们的那1秒io操作也没有让cpu进行傻等,所以对于cpu来说,io操作已经无法影响它的并发数了,因为它始终在工作,并没有浪费等待时间。

解析一下,如果使用异步的方式,那么会有两个比较关键的点:

  • 发起io操作,添加回调函数
  • 等任务完成后执行回调函数

异步编程完全没有浪费cpu一点性能,那如果所有的io耗时操作都用异步操作会怎么样呢?
了解node.js的朋友可能经常听见一个词回调地狱

前端开发中很少会有人在Ajax中嵌套Ajax,但是如果你想通过异步的方式来提升代码的性能,那么不可避免的,只要你的程序中有多个io操作,那它们就会向下面这段代码一样变成层层嵌套,很快这段代码就变得不可维护了,甚至是修改的时候都会让人十分头疼。


login(user => {
    getStatus(status => {
        getOrder(order => {
            getPayment(payment => {
                getRecommendAdvertisements(ads => {
                    setTimeout(() =>
首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇PHP SPL SplFileInfo FilterItera.. 下一篇Linux安装PHP8 新版笔记

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目