php-msf源码分析
发布时间:2022-07-02 17:18:58 所属栏目:PHP教程 来源:互联网
导读:源码解读也做了一段时间了, 总结一下自己的心得: 抓住 生命周期, 让代码在你脑海中 跑起来 分析架构, 关键字 分层 边界 隔离 一个好的框架, 弄清楚 生命周期 和 架构, 基本就已经到了 熟悉 的状态了, 之后是填充细节和编码熟练了 这里再介绍几个次重要的心得
源码解读也做了一段时间了, 总结一下自己的心得: 抓住 生命周期, 让代码在你脑海中 跑起来 分析架构, 关键字 分层 边界 隔离 一个好的框架, 弄清楚 生命周期 和 架构, 基本就已经到了 熟悉 的状态了, 之后是填充细节和编码熟练了 这里再介绍几个次重要的心得: 弄明白这个工具擅长干什么, 适合干什么. 这个信息也非常容易获取到, 工具的文档通常都会显眼标注出来, 可以通过这些 功能/特性, 尝试以点见面 根据这张图来思考 生命周期 & 架构, 这里就不赘述了, 这里分析一下 msf 中一些技术点: 协程相关知识 msf 中技术点摘录 协程 我会用我的方式来讲解, 如果需要深入了解的, 可以看我后面推荐的资源. 类 vs 对象 是一组很重要的概念. 类代表我们对事物的抽象, 这个抽象的能力在我们以后会一直用到, 希望大家有意识的培养这方面的意识, 至少可以起到触类旁通的作用. 对象是 实例化 的类, 是 真正干活的, 我们要讨论的 协程, 就是这样一个 真正干活的 角色. 协程从哪里来, 到哪里去, 它是干什么的? 想一想这几个简单的问题, 也许你对协程的理解就更深刻了, 记住这几个关键词: 产生. 需要有地方来产生协程, 你可能不需要知道细节, 但是需要知道什么时候发生了 调度. 肯定是有很多协程一起工作的, 所以需要调度, 怎么调度的呢? 销毁. 是否会销毁? 什么时候销毁? 当然, 大致 就是还有需要注意的地方 协程调度顺序, 如果不注意, 就可能会退化成同步调用. 调用链: 使用 yield 的调用链上, 都需要加上 yield. 比如下面这样: function a_test() { return yield $this->getRedisPool('tw')->get('apiCacheForABCoroutine'); } $res = yield a_test(); 如果不加 yield, 就变成了同步执行,对比一下 swoole2.0 的协程方案: $server = new SwooleHttpServer("127.0.0.1", 9502, SWOOLE_BASE); $server->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', $redis_res = $redis->recv(); $mysql_res = $mysql->recv(); $http_res = $httpclient->recv(); $response->end('Test End'); });//phpfensi.com $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 的原生方式, 理解起来其实更容易, 只需要知道协程 生成/调度/销毁 的时机就可以用好 fpm worker : http request = 1 : 1 swoole worker : http request = 1 : n 所以, 我们就需要一种新的方式, 来进行 request 间的隔离. 在编程语言里, 有一个专业词汇 scope(作用域). 通常会使用 scope/生命周期, 所以我一直强调的生命周期的概念, 真的很重要. swoole 本身是实现了隔离的: $http = new swoole_http_server("127.0.0.1", 9501); $http->on('request', function ($request, $response) { $response->end("<h1>Hello Swoole. #".rand(1000, 9999)."</h1>"); }); $http->start(); msf 在 Context 上还做了一层封装, 让 Context 看起来 为所欲为: // 你几乎可以用这种方式, 完成任何需要的逻辑 $this->getContext()->xxxModule->xxxModuleFunction(); 细节可以查看 src/Helpers/Context.php 文件 对象池: 对象池这个概念, 大家可能比较陌生, 目的是减少对象的频繁创建与销毁, 以此来提升性能, msf 做了很好的封装, 使用很简单: // getObject() 就可以了 /** @var DemoModel $demoModel */ $demoModel = $this->getObject(DemoModel::class, [1, 2]); 对象池的具体代码在 src/Base/Pool.php 下: 底层使用反射来实现对象的动态创建 public function get($class, ...$args) return $obj; } else { // 使用反射 $reflector = new ReflectionClass($poolName); $obj = $reflector->newInstanceWithoutConstructor(); $obj->__useCount = 0; $obj->__genTime = time(); $obj->__isConstruct = false; $obj->__DSLevel = Macro::DS_PUBLIC; unset($reflector); //phpfensi.com return $obj; } } 使用 SplStack 来管理对象 private function applyNewPool($poolName) { if (array_key_exists($poolName, $this->map)) { throw new Exception('the name is exists in pool map'); } $this->map[$poolName] = new SplStack(); return $this->map[$poolName]; } // 管理对象 $pool->push($classInstance); $obj = $pool->shift(); (编辑:云计算网_泰州站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |