swoole 第1章 前言 swoole 第1章 前言

2021-06-09

一、什么是 swoole

swoole 是基于 C 开发的一个 php 扩展,类似你熟悉的  Mysqli、cURL 等等。

swoole 的作用,其实更多的是解决 php 在某些方面的缺陷(当然,php 是最好的语言),比如即时通讯、异步任务、消息队列等等。

Swoole 是 PHP 语言的高性能网络通信框架,提供了 PHP 语言的异步多线程服务器,异步 TCP/UDP 网络客户端,异步 MySQL,数据库连接池,AsyncTask,消息队列,毫秒定时器,异步文件读写,异步 DNS 查询。

Swoole 虽然是标准的 PHP 扩展,实际上与普通的扩展不同。普通的扩展只是提供一个库函数。而 swoole 扩展在运行后会接管 PHP 的控制权,进入事件循环。当 IO 事件发生后,swoole 会自动回调指定的 PHP 函数。

二、php 的 cli 模式

PHP 除了可以被 Apache IIS 等服务器调用,还可以通过 cli 模式运行,因为 php 本质上还是 C 语言写的程序。

①、将 php.exe 加入环境变量

②、新建 cli.php

 echo "hello php cli\n";

③、打开 cmd ,切换到 cli.php 所在目录,输入

php cli.php

④、修改 cli.php

echo "hello php cli\n";
var_dump($_SERVER["argc"]);   //$_SERVER["argc"]  为传递的参数的个数
var_dump($_SERVER["argv"]);   //S_SERVER["argv"]  为传递的参数的值,以数组表示

⑤、打开 cmd ,切换到 cli.php 所在目录,输入

php cli.php one two

返回:

hello php cli
int(3)
array(3) {
  [0] =>
  string(8) "test.php"
  [1] =>
  string(3) "one"
  [2] =>
  string(3) "two"
}

三、进程和线程

①、进程

对于操作系统而言,进程就是一个任务,比方说你打开了一个记事本,那就启动了一个进程,打开了两个浏览器,就是另外开启了两个进程,再或者说我现在在 word 内写文章,打开 word 也会占用一个进程。也就是说,一个进程至少要干一件事情。

对于 linux 系统而言,如果你想要查看当前系统中运行着哪些进程,可以通过 ps 命令进行查看。

比如我现在打开一个终端,用 vim 打开一个文件

vim test.php

打开后这个终端不动,再新打开一个终端,执行ps命令后

ps aux | grep vim
root      8381  0.0  0.4 143844  4724 pts/0    S+   09:30   0:00 vim test.php
root      8876  0.0  0.0 103324   884 pts/2    S+   09:40   0:00 grep vim

可以看到,有两个 vim 相关的进程在我执行ps的那一霎那还在执行。

②、线程

有些情况下,一个进程会同时做一些事情,比如说 word。它可以同时进行打字、拼写检查等操作。注意这里我们说的同时进行。像这样,在一个进程内部,同时运行着多个“子任务”,我们就可以把这些子任务称之为“线程”。即进程是由多个线程组成的,一个进程至少要有一个线程。实际上,线程是操作系统最小的执行单元。

③、多任务的实现

A、试想一下,如果我们要同时执行多个任务怎么办?

根据上文的理解,我们可以:启动多个进程

B、试想一下,如果我们要同时执行多个任务怎么办?根据上文的理解,我们可以

  • 启动多个进程

  • 启动一个进程,并在该进程内启动多个线程

  • 启动多个进程,每个进程内启动多个线程

④、多进程实现

我们举一个实际点的例子:各位熟悉的 apache,其实就是一种多进程实现的案例。当父进程监听到有新的请求时,就会 fork 出新的子进程来对之进行处理。

Linux 的 fork() 函数通过系统调用即可实现创建一个与原进程几乎相同的进程。对于多任务,通常我们会设计 Master-Worker 模式,即一个 Master 进程负责分配任务,多个 Worker 进程负责执行任务。同理,如果是多线程,Master 就是主线程,Worker 就是子线程。

⑤、多进程与多线程的区别

多进程的优点就是稳定性很高,如果一个进程挂了,不会影响其他子进程,当然,如果主进程挂了那就都玩完(主进程挂点的可能性微乎其微,后面讲进程模型会说到)。而对于多线程,这个恐怕就是致命的缺点了,因为所有线程共享内存,如果某一个线程挂了,那这个进程几乎就崩溃了。

性能方面,不论是进程还是线程,如果启动太多,无疑都会带来 CPU 的调度问题,因为进程或者线程的切换,本身就非常耗费资源。数量达到一定程度的时候,CPU 和内存就消耗殆尽,电脑就死机了。

举一个例子:使用过 windows 的用户都知道,如果我们打开的软件越多(开启的进程也就越多),电脑就会越卡,甚至装死机没反应。

线程与进程相比,自然是要比进程更轻量一些,而且线程之间是共享内存的,所以不同线程之间的交互就显得容易实现。而对于多进程之间的通信,需要借助消息队列,共享内存等复杂的方式才可以实现。

四、IO模型

①、什么是 IO

IO 即 Input/Output,输入和输出的意思。在计算机的世界里,涉及到数据交换的地方,比如磁盘、网络等,就需要 IO 接口。

通常,IO 是相对的。比如说你打开浏览器,通过网络 IO 获取我们网站的网页,浏览器首先会往服务器发送请求,这是一个 Output 操作,随后服务器给浏览器返回信息,这就是一个 Input 操作。以上都是基于浏览器而言。但是,有些操作就比较特殊。比如程序在运行时,数据被加载在内存中,通过程序往磁盘写数据,对内存而言,这就是单方面的的 Output。

②、IO模型

IO 模型通常有很多种,我们简单介绍下同步 IO 和 异步IO。

③、同步IO

实际上我们刚刚介绍的浏览器请求服务器的过程正是同步 IO 的例子。

那我们再比如,假设我们要通过程序往磁盘写大量的数据,如果没有磁盘 IO 操作,php 程序在内存中执行的速度是非常快的,但是磁盘写数据的过程相对而言就是漫长的,CPU 就需要等待磁盘 IO 操作之后才能继续执行其他代码,像上面这两种情况,我们都称之为同步 IO。

php 本身是单线程的,当 php 进程被挂起的时候,像上面的读取磁盘数据,往磁盘写数据,在 IO 操作之前 php 代码就没办法继续执行了。

因为 IO 操作阻塞了当前线程,如果某用户也想从磁盘上读取或者写数据,就需要等待。

有些人要反驳了,这不对呀,我经历不是这样的,很多人可以同时访问我的网站,这没问题的。

这个没必要纠结,php 本身是单进程单线程的,用户可以同时访问你的网站实际上是 web 服务器的功劳。这就是我们之前讨论过的,如何解决多任务的问题。

web 服务器的进程模型暂时不多讨论,免得懵。

如果不考虑 web 服务器,是不是当前进程一旦阻塞,其他人访问 php 都会被阻塞啦?答案是肯定的。要解决这个问题,有回到我们一直强调的多进程或者多线程。

但是,如果为了解决并发问题,系统开启了大量的进程,就像我们之前说的,操作系统在进程或者线程间切换同样会造成 CPU 大量的开销。有没有更好的解决方案呢?

④、异步IO

答案就就是异步 IO。我们再来强调一遍异步 IO 是要解决什么问题的:同一线程内,执行一些耗时的任务时,其他代码是不能继续执行的,要等待该任务操作完之后才可以。

异步 IO 是什么样的呢?当程序需要执行一个非常耗时的 IO 操作的时候,它只发出 IO 指令,不需要等待 IO 的结果,然后可以继续执行其他的代码了。当 IO 返回结果时,再通知 CPU 去处理,这就是异步 IO。

总结:同步 IO 模型下,主线程只能被挂起等待,但是在异步 IO 模型中,主线程发起 IO 指令后,可以继续执行其他指令,没有被挂起,也没有切换线程的操作。由此看来,使用异步 IO 明显可以提高了系统性能。

五、TCP/IP和UDP

①、浏览器访问网站的过程

平时我们打开一个浏览器,然后输入网址后回车,即展现了一个网页的内容。这是一个非常简单的操作。我们来简单的概括下背后的逻辑。

  • 浏览器通过 TCP/IP 协议建立到服务器的 TCP 连接

  • 客户端向服务器发送 HTTP 协议请求包,请求服务器里的资源文档

  • 服务器向客户端发送 HTTP 协议应答包,如果请求的资源包含有动态语言的内容,那么服务器会调用动态语言的解释引擎负责处理“动态内容”,并将处理得到的数据返回给客户端

  • 客户端与服务器断开,由客户端解释 HTML 文档,在客户端屏幕上渲染图形结果

表面上看这就是两台电脑之间进行的一种通信。

更确切的说,是两台计算机上两个进程之间的通信。你打开浏览器相当于启动了一个浏览器进程,而服务端事先也启动了某个进程,在某个端口监听,时刻等待客户端的连接。

那么问题来了,为什么客户端可以请求到服务器呢?服务器上跑那么多服务,又是怎么知道客户端想要什么呢?

其实答案很简单,因为有网络。计算机为了联网,就必须遵循通信协议。早期的互联网有很多协议,但是最重要的就非TCP协议和IP协议莫属了。所以,我们把互联网的协议简称为TCP/IP协议。

②、IP协议

想必大家都有过这样的经历,客户端通过 telnet 连接服务器的时候,往往都需要一个 ip 地址和一个端口。如果客户端跟服务器之间有数据的交互,其过程大致是这样的:

IP 协议负责把你本机的数据发送到服务端,数据被分割成一块一块的。然后通过 IP 包发送出去。IP 包的特点是按块发送,但不保证能到达,也不保证数据块依次到达。

如果是这样进行数据传输,服务器根本不能保证接收到的数据的完整性和顺序性,这样是不是就会有很大的问题呢?

③、TCP协议

于是乎,TCP 协议应运而生,它是建立在 IP 协议之上,专门负责建立可靠连接,并保证数据包顺序到达。TCP 协议会通过握手建立连接,然后,对每个 IP 包编号,确保对方顺序收到,如果出现丢包,则重新发送。

这个时候再说 TCP 协议是一种面向连接、可靠的、基于 IP 之上的传出层协议就不难理解了吧。

TCP 协议还有一个更重要的特点,它是基于数据流的。

什么意思呢?这就好比客户端和服务端要进行数据交互,中间有一个管子连接着,这个时候交互数据就好比管子中的水,当数据在传输(水在流动)的过程中,服务端是无法知道哪段数据是我们想要的完整数据。怎么解决这一问题呢?这个时候就需要双方约定一个协议来解决了。再往后说就说到应用层协议了,比如 http 协议,我们姑且不谈。

④、UDP协议

TCP 懂了,UDP 自然就不难理解了。

相对于 TCP,使用 UDP 协议进行通信的最大区别就是,UDP 不需要建立连接,给他一个 ip 和端口,就可以直接发送数据包了。但是,能不能成功到达就不知道了。虽然 UDP 传输不可靠,但是速度快。对于一些对数据要求不高的场景,使用 UDP 通信无疑是不错的选择。

打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,你说多少就多少

打开微信扫一扫,即可进行扫码打赏哦

阅读 905