前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >PHP网络编程之epoll开启篇

PHP网络编程之epoll开启篇

作者头像
老李秀
发布2020-02-19 11:46:58
2.9K3
发布2020-02-19 11:46:58
举报

大家好,我是Old.Li。

这个公众号自从去年6月份到现在已经半年了,将近80篇的原创大概换来了550元的广告费。这不是我一个人的钱(主要是大家浏览量带来的支持),再加上我们最近遇到的事情,在避开了一大坨不靠谱的虚假公益组织后,我拿出了300元(惭愧不算多)捐献给了北京韩红爱心慈善基金会。转账的时候是用我个人建行的网银捐献的,附言名义是[ 老李的朋友们和老李 ],捐献渠道是我从韩红老师的weibo上找到的一个招商银行的对公银行账号,但目前我有两个尚无法确认:

  • 一是个人银行向对公银行转账是否成功了(因为转账电子回执不代表对方一定收到,但对方没收到这笔钱一定会被银行退回来的)
  • 二是附言名义不知道是否会被显示

所以,我就[ 以两天内这300块是不是被莫名其妙退回到我建行 ]为判断标准吧,上个图:

我告诉你们外面疫情这么垃圾,国家又免费赠送假期,这么好的时间如果你们能用在学习上,一定能xue微有点儿进步...翻来覆去还是那句话:

你从哪儿还能找到这么好的不要钱、不割韭菜的社会主义PHP高性能网络编程教程?我就像躺在你瑞幸账号里的0折咖啡券,不仅热腾腾的,而且还喷喷香...

我可是一心向着明月,这明月可别照沟渠啊

我一直劝告大家不要过度地迷信崇热那些偏上层应用级的知识,不要做普通的CURD,要立志当花式CURD冠军,要耐住寂寞和枯燥多看基础。这么基础而又底层彪悍的知识不仔细研究仔细看,问我啥时候分享下Laravel教程...Laravel官方完善且好用的文档就是最好的Laravel教程,不要辜负人家官方啊;再说,主要是我也没用过那玩意。然后是别的我不敢说,就PHP而言我现在正在写的这一系列文章绝对是PHP中不算太常见且很底层基础的课程,了解了这些后你去研究或者使用Workerman以及swoole甚至NodeJS,都会底气足足的。

我用了四个章节,从开始介绍PHP socket基础,然后过渡到select IO复用,今天我要对select IO复用做个xue微简单而又枯燥的总结。

在一个可支撑高IO的服务器上,一个或者少数几个进程(线程)必须拥有同时支撑众多socket读写的能力,select IO复用是使得我们初步拥有这种能力的初级解决方案。假设一个HTTP服务器,我们关注众多socket(也就是浏览器链接)中有任意数量的socket有满足可读条件(也就是说浏览器GET或POST请求已经发送完毕),这里有个操作就是select调用会将我们关注的众多socket从用户空间复制到系统内核中去,然后此处的关键过程就是关注可读事件,而不是像呆B一样去不断recv每个socket是否有数据,而是关注可读事件,而是关注可读事件,而是关注可读事件,翻译到技术层面上就是阻塞在select系统调用上,一旦select系统调用发现可读条件就绪,此时的阻塞立马就会被化解掉,服务器程序就会立马开始向下执行。反应到程序上就是select会遍历关注的socket集合来发现哪些socket是O jb K的,然后针对这些socket进行逻辑处理。

然后,我再提出关于select的三个问题:

  • 首先是select可监控的socket fd数量有限,在PHP里包括文档等地方可能没有提,但是UNP或*NIX API手册中是有提示的,这个数量是1024,是由FD_SETSIZE宏确定的。有些地方可能会通过教大家修改这个宏的值然后重新编译*NIX,然后修改进程可操作文件描述符数量来实现“ 超频 ”版的select,这种骚操作至于你敢不敢做,反正我不敢
  • 其次是需要将监控的socket从用户态复制到内核态。啥叫用户态,啥叫内核态?目前为止,作为软件,只有操作系统可以几乎100%控制和利用硬件,而其他应用程序则只能通过利用操作系统提供的系统调用来利用硬件。一旦用户态应用程序执行了系统调用,比如调用select、调用socket_write()或socket_read()时当前状态就立马会从用户态流转到内核态中。比如调用socket_write()(底层应该就是write系统调用)向一个socket fd写数据,那么就需要将数据先从用户态复制到内核以及socket缓冲区,最后调用完成后还是要回到用户态的,这里涉及到了两次场景切换与一次复制(所以这里的高科技就是如何保存当前用户态的各种信息,好了打住,欲想了解更深刻请关注操作系统原理)。这里需要强调的是千万不要小看这个[ 从用户态复制到内核态 ]和[ 场景切换 ]过程,这个过程所耗费的时间、空间对宏观影响是相当巨大的!有些泥腿子可能听说过sendfile API,有些人可能是通过swoole文档了解到的,这个API可以节省复制次数和切换次数,有兴趣同学可以去了解下。在PHP里,我目前看到的只有eio_sendfile(),但我尚未看PHP源码并不能确认eio_sendfile()底层是否就是sendfile API
  • 最后是每次都要遍历所有的socket来查询具体是哪一个socket具备可读或可写条件。这个问题用心看并实践的腿子们一定会有疑问,就是PHP那个socket_socket()返回的结果就是遍历过后的可读或可写socket集合啊,不需要我们自己遍历的。这个咋说呢,大概是PHP给抽象处理一下,在C语言里使用select系统调用的时候,我们是需要遍历每一个socket的,在每一个socket使用FD_ISSET宏判断其是否满足可读或可写。要知道这种遍历的时间复杂度可是O(n),我这么一说是不是菊花紧了一下?

泥腿铁子们,上面这一大段我还缩减了一诸如sendfile、mmap、系统中断、write\read系统调用具体过程等等等等一大坨基础细节,所以请这边儿的朋友、楼上的朋友、那边树上的朋友,请大声告诉我:基础恶不恶心?

所以针对select存在着的这三大问题,*NIX中又打了一坨补丁缝缝补补地搞出来一个叫做poll的,不过poll酱只是解决了一下1024的问题,算是临时应急解决方案。然后是PHP里好像是没有可以操作到poll的函数,大概是我没找到,有知道的大佬可以后台发消息提醒下,我会补充在下篇里。

总之大家也都知道,每当到了这个时候,总是会有一个英雄,TA脚踩着七彩祥云,来替大家背锅...TA就是epoll。epoll完美解决了select的缺陷 --- 能用!你看下啊,epoll天生的技能指标就很针对select那些缺点,我写下你们感受一下:

  • 1024限制没有...理论无限大,大!大!大!好凶!
  • 真的只返回具备满足可读/可写的socket,咻咻咻!
  • 最后我纠正一个我之前在Advanced-PHP中一个结论,就是epoll中使用了mmap。最近我在看epoll的时候,好像并没有发现mmap相关~

然而在PHP中,泥,并不能找到可以直接操控epoll的函数方法,泥,只能求助于著名事件库 --- Libevent。Libevent有着一个极为接地气而又诚恳的官网,大概长这样你们感受一下:

看到没有,这个朴素的网页上信誓旦旦地说Libevent支持poll、kqueue、select、epoll等一大坨,并称Libevent还能在Linux、BSD、Mac、Solaris、Windows等上编译通过...

而PHP如果要操作Libevent,那么就需要event扩展,具体地址大家可以到pecl上搜索一下。至于这玩意怎么安装我坚信这个不需要我教了...

所以总结下Libevent就是一个事件库,TA对市面上各种常用的IO复用技术的统一封装,而且Libevent本身跨平台。除了提供最基础的事件库功能外,Libevent还提供了DNS、Http服务等相关工具集,这些我们将在后面章节里逐一展开演示。

我们把内容尝试升华一个层次,就是你要知道Libevent这个层次的内容:这种事件库都是高并发高IO软件的底层基石。Memcache的事件就是基于Libevent构建的,Redis的事件则是自研一套简易版" Libevent ",NodeJS的事件则是基于Libuv,同级别还有一个叫做Libev的竞争对手。话说到这里就是说能无论你工作中是用到了Memcache还是Redis又或者NodeJS,至少在事件这块儿,只要你能整明白Libevent,这块儿瞬间就打通了。有些人疲于在面试前、工作中不断背诵记忆各种不同上层应用的花哨技巧,而有些人只整明白这些上层应用下的基于同样原理的基石 --- 全中。

除此之外还有一件事儿,就是本系列文章我打算改名为《PHP网络编程》或《高性能PHP网络编程》,我纠结的地方在于[ 高性能 ]三个字加在前面未免xue微有点儿膨胀,这个大家方便的话给个投票吧,你们说了算。然后是划重点:这一系列文章我会开源到github上,有兴趣的同学wechat call我,我会建个github team,算是职业生涯中一起为PHP做的最后一点儿贡献啦~

至于书籍的目录我下篇文章会发出来。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-02-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 高性能API社区 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 Redis
腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档