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

<?php
   echo "hello php cli\n";

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

php cli.php

④、修改 cli.php

<?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通信无疑是不错的选择。


阅读 123