• 欢迎来到本博客,希望可以y一起学习与分享

swoole笔记

PHP benz 3年前 (2018-05-26) 162次浏览 0个评论 扫描二维码
文章目录[隐藏]

详细教程:https://blog.csdn.net/column/details/swoole-link.html

一、进程相关知识

在操作系统中,一个进程就是一个正在运行的程序,在内存驻存,申请属于它的内存空间。一个进程包括内存空间与上下文环境。一个进程可以通过系统函数创建多个子进程。子进程被创建的时候会复制父进程的内存与上下文环境,也就是说子进程与子进程之间、子进程与父进程之间是相互独立的,修改某个子进程不会影响到其他子进程以及其父进程。子进程会复制父进程的I/O句柄(fd描述符);

共享内存

进程之间是相互独立的,那么它们之间如何通讯的呢?—–使用共享内存(进程之间通讯有多种方法,这是其中之一)。

共享内存既不依赖于任何进程,也不属于任何进程,通过系统函数创建出共享内存并指定索引,任何进程根据索引可以申请内存空间,并存取数据。也就是

  • 共享内存不属于任何一个进程
  • 在共享内存中分配的内存空间可以被任何进程访问
  • 即使进程被关闭,共享内存仍然可以继续保留

swoole结构

为了解决每次请求都要启动进程,由于启动进程非常消耗时间,于是swoole采用以下结构:


Master : 是swoole的主进程,master拥有多个Reactor线程,每个Reactor线程都运行了一个epoll函数的实例,swoole的所有事件的监听都在Reactor线程实现,比如:来自客户端的连接、管道的通讯等。

Manager : 是一个进程管理与分配,用于创建和管理下面的worker与task。

工作进程 : 有两种类型,一个是Worker,另一个是Task

Worker : swoole的主逻辑进程,处理各种请求与事件

Task : swoole提供的异步工作进程,用于处理耗时较长的同步任务

在swoole当中,进程与进程之间是通过管道来通讯的。

流程

当Master接收到客户端的请求,通过管道把请求发给Worker进程进行处理,如果Worker进程有需要投递任务到Task进程时,通过管道把任务投递到Task进程。当Task把任务处理完,返回结果给Worker,Worker处理完后,通知Master的Reactor线程,Reactor线程把结果返回给客户端。如果某个Worker出现故障,Manager就会迅速拉起一个Worker进程,以确保Worker进程数是固定的。

Task

Task进程独立处理,耗时长的任务,提高了Worker的效率。Worker进程与Task进程相互调用如下:

Worker通过task()函数向Task进程投递任务,Task进程通过onTask()函数监听任务投递事件来接收任务,任务处理完后,通过finish()函数返回结果,Worker通过onFinish()函数监听Task进程任务结束事件,接收任务处理完的结果。
Worker进程与Task进程间通过Unix Socket管道通讯(也可以配置,通过消息队列来进行通讯)

Task常见问题

Task传递数据大小
数据小于8K : 直接通过管道传递;
数据大于8K : 写入临时文件传递

Task传递对象
可以通过序列化传递一个对象的拷贝;
Task中对对象的改变不会反映到Worker进程中;
数据库连接、网络连接对象不可传递;

Task的onFinish回调
Task的onFinish回调会发回调用task方法的worker进程

Timer定时器

Timer在1.7以前,是一个线程,通过一定的时间间隔循环检查每个定时器是否可以被调用,后来发现这种方法创建的定时器不够多,因为每次遍历需要的时间非常长,而且会出现前面的定时器还没执行完,后面的定时器就开始执行了。还有就是可能由于某种原因导致Timer定时器在运行中挂掉。
在新版本中,Timer定时器做了如下改进:
基于Reactor线程(在Task Worker中使用系统定时器)。
基于epoll的timeout机制实现,如果在指定时间没处理完事件,就会中断,并调用指定函数,查找所有定时器是否能被运行。
使用最小堆存放timer,提高检索效率。距离下一次运行的剩余时间越小,就越接近堆顶。

Timer常见问题

Timer参数传递
可以通过tick方法的第三个参数传递,也可以使用use闭包

Timer传递对象
onTimer是在调用tick方法的进程中回调,因此可以直接使用在Worker进程中声明的对象 (局部变量无法访问)
Timer的清除
Tick方法会返回timer_id,可以使用swoole_timer_clear清除指定放入定时器

进程间通讯方式

管道

管道是一组(2个) 特殊的描述符
管道需要在fork函数调用前创建
如果某一端主动关闭管道,另一端的读取操作会直接返回0

消息队列

通过指定key创建一个消息队列
在消息队列中传递的数据有大小限制(大约是一个int型)
消息队列会一直保留直到被主动关闭。有利于进程故障后重新拉起的进程能继续执行故障时未被完成的任务

IO多路复用

epoll函数会监听注册在自己名下的所有的socket描述符
当有socket感兴趣的事件发生时,epoll函数才会响应,并返回有事件发生的socket集合
epoll的本质是阻塞IO,它的优点在于能同时处理大量socket连接

Event Loop


Event Loop 是一个Reactor线程,其中运行了一个epoll实例
可通过接口添加socket描述符到epoll监听中,并指定事件响应的回调函数
Event Loop不可用于FPM环境下。因为一个请求结束,FPM进程就有可能被关掉,导致注册的事件不可能被监听,从而导致错误

常见问题

为什么开启了Event Loop的程序会一直运行不停止
开启Event Loop后,程序内会启动一个线程并一直阻塞在epoll的监听上,因此不会退出

如何关闭Event Loop
调用swoole_event_exit 函数即可关闭事件循环(注意:swoole_server程序中此函数无效)

Process

基于C语言封装的进程管理模块,方便PHP的多进程编程
内置管道、消息队列接口,可方便实现进程间通讯
提供自定义信号管理


文章 swoole笔记 转载需要注明出处
喜欢 (0)

您必须 登录 才能发表评论!