加入收藏 | 设为首页 | 会员中心 | 我要投稿 核心网 (https://www.hxwgxz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程 > 正文

php-msf源码详解

发布时间:2021-04-02 12:31:19 所属栏目:编程 来源:网络整理
导读:我们来看分享下具体源码: 源码解读也做了一段时间了,总结一下自己的心得: 抓住 生命周期,让代码在你脑海中 跑起来 分析架构,关键字 分层 边界 隔离 一个好的框架,弄清楚 生命周期 和 架构,基本就已经到了 熟悉 的状态了,之后是填充细节和编码熟练了 这里再
副标题[/!--empirenews.page--]

我们来看分享下具体源码:

源码解读也做了一段时间了,总结一下自己的心得:

抓住 生命周期,让代码在你脑海中 跑起来

分析架构,关键字 分层 边界 隔离

一个好的框架,弄清楚 生命周期 和 架构,基本就已经到了 熟悉 的状态了,之后是填充细节和编码熟练了

这里再介绍几个次重要的心得:

弄明白这个工具擅长干什么,适合干什么. 这个信息也非常容易获取到,工具的文档通常都会显眼标注出来,可以通过这些 功能/特性,尝试以点见面

从工程化的角度去看这个项目,主要和上面的 架构 区分,在处理核心业务,也就是上面的 功能/特性 外,工程化还涉及到 安全/测试/编码规范/语言特性 等方面,这些也是平时在写业务代码时思考较少并且实践较少的部分

工具的使用,推荐我现在使用的组合: phpstorm + 百度脑图 + Markdown笔记 + blog和 php-msf 的渊源等写技术生活相关的 blog 再来和大家八,直接上菜.

生命周期 & 架构

官方文档制作了一张非常好的图: 处理请求流程图. 推荐各位同仁,有闲暇时制作类似的图,对思维很有的帮助.

根据这张图来思考 生命周期 & 架构,这里就不赘述了,这里分析一下 msf 中一些技术点:

协程相关知识

msf 中技术点摘录

协程

我会用我的方式来讲解,如果需要深入了解的,可以看我后面推荐的资源.

类 vs 对象 是一组很重要的概念. 类代表我们对事物的抽象,这个抽象的能力在我们以后会一直用到,希望大家有意识的培养这方面的意识,至少可以起到触类旁通的作用. 对象是 实例化 的类,是 真正干活的,我们要讨论的 协程,就是这样一个 真正干活的 角色.

协程从哪里来,到哪里去,它是干什么的?

想一想这几个简单的问题,也许你对协程的理解就更深刻了,记住这几个关键词:

产生. 需要有地方来产生协程,你可能不需要知道细节,但是需要知道什么时候发生了

调度. 肯定是有很多协程一起工作的,所以需要调度,怎么调度的呢?

销毁. 是否会销毁? 什么时候销毁?

现在,我们再来看看协程的使用方式对比,这里注意一下,我没有用 协程的实现方式对比,因为很多时候,需求实际是这样的:

怎么实现我不管,我选最好用的.

getRedisPool('tw')->get('apiCacheForABCoroutine'); // msf - 并发协程调用 $client1 = $this->getObject(Client::class,['http://www.baidu.com/']); yield $client1->goDnsLookup(); $client2 = $this->getObject(Client::class,['http://www.qq.com/']); yield $client2->goDnsLookup(); $result[] = yield $client1->goGet('/'); $result[] = yield $client2->goGet('/');

大致 是这样的一个等式: 使用协程 = 加上 yield,所以搞清楚哪些地方需要加上 yield 就好了 -- 有阻塞IO的地方,比如 文件IO,网络IO(redis/mysql/http) 等.

当然,大致 就是还有需要注意的地方

协程调度顺序,如果不注意,就可能会退化成同步调用.

调用链: 使用 yield 的调用链上,都需要加上 yield. 比如下面这样:

getRedisPool('tw')->get('apiCacheForABCoroutine'); } $res = yield a_test(); // 如果不加 yield,就变成了同步执行

对比一下 swoole2.0 的协程方案:

set([ 'worker_num' => 1,]); // 需要在协程 server 的异步回调函数中 $server->on('Request',function ($request,$response) { $tcpclient = new SwooleCoroutineClient(SWOOLE_SOCK_TCP); // 需要配合使用协程客户端 $tcpclient->connect('127.0.0.1',9501,0.5) $tcpclient->send("hello worldn"); $redis = new SwooleCoroutineRedis(); $redis->connect('127.0.0.1',6379); $redis->setDefer(); // 标注延迟收包,实现并发调用 $redis->get('key'); $mysql = new SwooleCoroutineMySQL(); $mysql->connect([ 'host' => '127.0.0.1','user' => 'user','password' => 'pass','database' => 'test',]); $mysql->setDefer(); $mysql->query('select sleep(1)'); $httpclient = new SwooleCoroutineHttpClient('0.0.0.0',9599); $httpclient->setHeaders(['Host' => "api.mp.qq.com"]); $httpclient->set([ 'timeout' => 1]); $httpclient->setDefer(); $httpclient->get('/'); $tcp_res = $tcpclient->recv(); $redis_res = $redis->recv(); $mysql_res = $mysql->recv(); $http_res = $httpclient->recv(); $response->end('Test End'); }); $server->start();

使用 swoole2.0 的协程方案,好处很明显:

不用加 yield 了

并发调用不用刻意注意 yield 的顺序了,使用 defer() 延迟收包即可

但是,没办法直接用 使用协程 = 加上 yield 这样一个简单的等式了,上面的例子需要配合使用 swoole 协程 server + swoole 协程 client:

server 在异步回调触发时 生成协程

client 触发 协程调度

异步回调执行结束时 销毁协程

这就导致了 2 个问题:

不在 swoole 协程 server 的异步回调中怎么办: 使用 SwooleCoroutine::create() 显式生成协程

需要使用其他的协程 Client 怎么办: 这是 Swoole3 的目标,Swoole2.0 可以考虑用协程 task 来伪装

这样看起来,好像 使用协程 = 加上 yield 这样要简单一些? 我不这样认为,补充一些观点,大家自己斟酌:

使用 yield 的方式,基于 php 生成器 + 自己实现 PHP 协程调度器,想要用起来不出错,比如上面 协程调度顺序,你还是需要去弄清楚这块的实现

Swoole2.0 的原生方式,理解起来其实更容易,只需要知道协程 生成/调度/销毁 的时机就可以用好

Swoole2.0 这样异步回调中频繁创建和销毁协程,是否十分损耗性能? -- 不会的,实际是一些内存操作,比进程/对象小很多

msf 中技术点摘录

msf 在设计上有很多出彩的地方,很多代码都值得借鉴.

请求上下文 Context

这是从 fpm 到 swoole http server 非常重要的概念. fpm 是多进程模式,虽然 $_POST 等变量,被称之为超全局变量,但是,这些变量在不同 fpm 进程间是隔离的. 但是到了 swoole http server 中,一个 worker 进程,会异步处理多个请求,简单理解就是下面的等式:

所以,我们就需要一种新的方式,来进行 request 间的隔离.

在编程语言里,有一个专业词汇 scope(作用域). 通常会使用 scope/生命周期,所以我一直强调的生命周期的概念,真的很重要.

(编辑:核心网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读