加入收藏 | 设为首页 | 会员中心 | 我要投稿 云计算网_泰州站长网 (http://www.0523zz.com/)- 视觉智能、AI应用、CDN、行业物联网、智能数字人!
当前位置: 首页 > 站长学院 > PHP教程 > 正文

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(); 

(编辑:云计算网_泰州站长网)

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

    热点阅读