PHP下用Swoole实现Actor并发模型的方法_php实例

来源:脚本之家  责任编辑:小易  

  一直想写点Swoole的东西,毕竟它重新定义了php,却一直不知道怎么下手写Swoole涉及的知识点非常多,互为表里,每次想写都发现根本理不出一个头绪Swoole是一个php的扩展,它的核心目的就是解决e799bee5baa6e79fa5e98193e4b893e5b19e31333361326330php在实现server服务中可能遇到的一系列问题,这些问题用源生的php往往并不能很高效(执行效率)的解决,一般也不会使用php来解决,所以会有说swolle重新定义的php的说法。  其实swoole也提供了一个框架,swoole framework是基于swoole extension设计的一个框架,要用好这个框架,还是要先了解swoole extension。  扩展的英文名称是Extension,php扩展是用C语言作为开发语言,基于Zend引擎提供的API,编译成的一个动态库。  如果曾经做过类似动态库调用开发的童鞋可能会更好理解一些,例如Android中的NDK开发在php的配置文件中配置好extension的属性后,就可以引用这个动态库了。  也就是说,swoole本身是用C语言编写的,它可以让php获得一些额外的function。  然后是运行方式,swoole的许多功能都只能运行在cli模式下,而cli模式往往是很多刚接触swoole的phper遇到的第一个问题。  有时候其实只是需要转变一下思路  我们现在整理一下最常见的php代码执行方式:  安装apache、php  配置apache对那个目录进行php解析  用浏览器访问那个目录的php文件  更多的细节这里就不提了,毕竟我相信每个phper对这个都是很熟悉的。  但这里就开始出现了第一个问题,我们知道,php是一个脚本语言,脚本语言的核心特点在于不用编译,随时执行,而执行脚本的工具就是解析器,而php的解析器就是zend引擎。  严格来说,zend并不是唯一的选择,不过,zend是最官方的。另外,Zend Studio和Zend Engine不是同一个东西,本文中的Zend全部指Zend Engine。  换个角度讲,只要有解析器,写好的php脚本就是可以执行的,而zend引擎与apache之间并没有绝对的关系实际上,apahce是调用了zend对php脚本进行执行,然后将执行结果输出给了浏览器所以所谓cli模式(CommandLine,命令行模式),其实就是在命令行下直接调用zend引擎对php脚本进行解析并执行,并获得程序输出结果的php脚本执行方式。  其实php也可以作为shell脚本来使用哦,就像bash shell一样既然问题讲清楚了,在一个系统中具体怎么操作呢?  本文以CentOS 7.5作为系统环境,swoole是针对linux系统开发的,windows下并不适用。学习swoole的一个前题是懂得基本的linux系统使用。  当安装好php的时候,找到php的安装目录,如果是默认安装的话,可以试试whereis命令# 某种简单的方法  whereis php  > /usr/local/bin/php;  locate whereis find这些命令都可以试试,目的是找到php然后我们来写一个最经典的php脚本:  <?php  //vi hello_cli.php  echo 'Hello PHP Cli';  编写纯php脚本时,php标签不要封口  然后我们在shell里执行它:  /usr/local/bin/php hello_cli.php  > Hello PHP Cli  这段代码中的第一个php,是一个可执行文件,它接受一个php脚本文件作为输入参数,并解析执行这个php脚本文件(通过zend)。  没有错,第一个cli模式下的php程序就被你执行成功了!  默认情况下,php都会被安装在了$PATH的目录下,那就可以直接省略路径前缀了,下文中调用php的时候,全都省略了路径前缀。  因为swoole是pecl的项目,所以使用pecl安装是最简单的方法,强烈推荐第一次接触的童鞋先使用pecl安装,在熟悉了swoole之后,再考虑使用编译安装的方式以获取更多进阶功能。  pecl这个工具基本都会被安装在与php相同的目录下(往往也都是$PATH目录)pecl install swoole  执行以下命令查看是否安装成功:  php -m | grep swoole  > swoole  如果正确的输出了swoole,那么恭喜你,这次安装很成功另一个常见的比较麻烦的问题是,有些童鞋的电脑里安装了多个php,而安装的时候没有正确的安装到预期的php的扩展目录中,就会导致无法正常工作,解决方案就是弄清楚各个php安装目录及配置关系,选择正确的目录进行安装。  其实本文还没正式开始介绍swoole,都是在学习swoole之前的准备工作,swoole的上手门槛比一般的php应用要高的多,如果没有网络开发和操作系统方面的一些知识,学习它并不是一件容易的事情,学习曲线很陡峭。  这句话我在群里说了无数次  很多新手会诟病swoole的手册写的太模糊,其实是前置知识不足,而手册也给出了需要的前置知识列表,以下引用至官网的手册-学习swoole需要哪些知识?  多进程/多线程  了解Linux操作系统进程和线程的概念  了解Linux进程/线程切换调度的基本知识  了解进程间通信的基本知识,如管道、UnixSocket、消息队列、共享内存socket  了解SOCKET的基本操作如accept/connect、send/recv、close、listen、bind了解SOCKET的接收缓存区、发送缓存区、阻塞/非阻塞、超时等概念IO复用  了解select/poll/epoll  了解基于select/epoll实现的事件循环,Reactor模型了解可读事件、可写事件  TCP/IP网络协议  了解TCP/IP协议  了解TCP、UDP传输协议  调试工具  使用gdb调试Linux程序  使用strace跟踪进程的系统调用  使用tcpdump跟踪网络通信过程  其他Linux系统工具,如ps、lsof、top、vmstat、netstat、sar、ss等学习并理解一个新事务并不是一个容易的事情,特别对于swoole这种具备一定颠覆性的工具,要有耐心和实践。  淡定的把手册看完,遇到不理解的名词学会使用搜索引擎学习,swoole的手册其实是个大宝库,网络开发常见的问题其实里边都涉及到了。  www.zgxue.com防采集请勿采集本网。

什么是Actor?

Swoole的优势 Swoole开源项目就是为了弥补PHP在这些方面的缺陷诞生的。与WordPress这些产品不同,PHP可以基于swoole去实现过去PHP无法实现的功能。Swoole为PHP打开了通往另一个世界的大门。

Actor对于PHPer来说,可能会比较陌生,写过Java的同学会比较熟悉,Java一直都有线程的概念(虽然PHP有Pthread,但不普及),它是一种非共享内存的并发模型,每个Actor内的数据独立存在,Actor之间通过消息传递的形式进行交互调度,且Actor是一种高度抽象化的编程模型,非常适合于游戏、硬件行业。

public function onReceive($serv,$fd,$from_id,$data) { 使用json_decode 解析任务数据 areas=json_decode($data,true);foreach($areas as$area){ 投递异步任务 serv->task($area);} }

Swoole协程与信箱

3、集成大量,使用的功能,比如方便的数据库操作,模板操作,缓存操作,系统配置,表单处理,分页,数据调用,字典操作,上传处理,内容编辑,调试等 4、模板-数据反射系统,可以直接在模板中调用数据,

得益于Swoole4.x,我们可以基于Swoole的协程与Channel快速实现一个信箱模式调度。模拟代码如下:

在php的web控制器中,每当更新了数据库的数据库后,我需要将这些数据发送到其他用户的客户端,不知在web控制器中怎么实现这个一个目的,怎么才能swoole_websocket_server发送这些最新的数据。

use Swoole\Coroutine\Channel;go(function (){ //创建十个信箱通道 $mailBoxes = []; for ($i = 1;$i <= 10;$i++){ $mailBoxes[$i] = new Channel(16); } //模拟master 邮局调度,随机像一个信箱投递消息 go(function ()use($mailBoxes){ while (1){ \co::sleep(2); $key = rand(1,10); ($mailBoxes[$key])->push(time()); } }); //模拟actor 实体消费 for ($i = 1;$i <= 10;$i++){ go(function ()use($mailBoxes,$i){ while (1){ $msg = ($mailBoxes[$i])->pop(); echo "Actor {$i} recv msg : {$msg} \n"; } }); }});

MySQL数据库的主从同步是通过解析Master库中的binary-log来进行同步数据到从库的。然而我们使用PHP来同步数据的时候,那么只能从master库分批查询数据,然后插入到南宁的slave库来了。

以上代码执行输出:

php test.php

Actor 8 recv msg : 1559622691

Actor 10 recv msg : 1559622693

Actor 1 recv msg : 1559622695

Actor 5 recv msg : 1559622697

协程通道每次在POP遇到无数据的时候,都会自动让出执行权(具体可以去看Swoole协程调度)

Actor库

基于上面的原理,我们实行了一个多进程分布的协程Actor库

composer require easyswoole/actor=2.x-dev

我们依赖dev库进行测试,生产可以自己依赖stable版本

进程关系

Easyswoole的Actor模型中,存在两组进程,一组是proxy进程,用来实现Actor对外服务,一组是worker进程,proxy进程与worker进程之间通过unixsock进行通讯,而Actor实例就均匀的分布worker之中。

样例代码

比如在一个聊天室中,我们可以定义一个房间模型。

namespace EasySwoole\Actor\Test;use EasySwoole\Actor\AbstractActor;use EasySwoole\Actor\ActorConfig;class RoomActor extends AbstractActor{ public static function configure(ActorConfig $actorConfig) { $actorConfig->setActorName('Room'); } public function onStart() { //每当一个RoomActor实体被创建的时候,都会执行该回调 var_dump('room actor '.$this->actorId().' start'); } public function onMessage($msg) { //每当一个RoomActor实体收到外部消息的时候,都会执行该回调当 var_dump('room actor '.$this->actorId().' onmessage: '.$msg); return 'reply at '.time(); } public function onExit($arg) { //每当一个RoomActor实体退出的时候,都会执行该回调 var_dump('room actor '.$this->actorId().' exit at arg: '.$arg); return 'exit at '.time(); } protected function onException(\Throwable $throwable) { //每当一个RoomActor出现异常的时候,都会执行该回调 var_dump($throwable->getMessage()); }}

在cli模式下创建一个Actor服务

use EasySwoole\Actor\Actor;use EasySwoole\Actor\Test\RoomActor;use EasySwoole\Actor\ProxyProcess;Actor::getInstance()->register(RoomActor::class);$list = Actor::getInstance()->generateProcess();foreach ($list['proxy'] as $proxy){ /** @var ProxyProcess $proxy */ $proxy->getProcess()->start();}foreach ($list['worker'] as $actors){ foreach ($actors as $actorProcess){ /** @var ProxyProcess $actorProcess */ $actorProcess->getProcess()->start(); }}while($ret = \Swoole\Process::wait()) { echo "PID={$ret['pid']}\n";}

创建一个cli测试脚本

use EasySwoole\Actor\Actor;use EasySwoole\Actor\Test\RoomActor;Actor::getInstance()->register(RoomActor::class);go(function (){ $actorId = RoomActor::client()->create('create arg1'); var_dump($actorId); \co::sleep(3); var_dump(RoomActor::client()->send($actorId,'this is msg')); \co::sleep(3); var_dump(RoomActor::client()->exit($actorId,'this is exit arg')); \co::sleep(3); RoomActor::client()->create('create arg2'); \co::sleep(3); RoomActor::client()->create('create arg3'); \co::sleep(3); var_dump(RoomActor::client()->sendAll('sendAll msg')); \co::sleep(3); var_dump(RoomActor::client()->status()); \co::sleep(3); var_dump(RoomActor::client()->exitAll('sendAll exit'));});

以上代码执行结果如下:

服务端

php test.php string(40) "room actor 00101000000000000000001 start"string(57) "room actor 00101000000000000000001 onmessage: this is msg"string(64) "room actor 00101000000000000000001 exit at arg: this is exit arg"string(40) "room actor 00101000000000000000002 start"string(40) "room actor 00103000000000000000001 start"string(57) "room actor 00101000000000000000002 onmessage: sendAll msg"string(57) "room actor 00103000000000000000001 onmessage: sendAll msg"string(60) "room actor 00101000000000000000002 exit at arg: sendAll exit"string(60) "room actor 00103000000000000000001 exit at arg: sendAll exit"

客户端

php test2.php string(23) "00101000000000000000001"string(19) "reply at 1559623925"string(18) "exit at 1559623928"bool(true)array(3) { [1]=> int(1) [2]=> int(0) [3]=> int(1)}bool(true)

更多细节可以在EasySwoole项目官网得到文档支持 http://easyswoole.com/

喜欢EasySwoole项目的,可以给个star https://github.com/easy-swoole/easyswoole

全异步非阻塞Server,可以同时支持数百万TCP连接在线基于websocket+flash_websocket支持所有浏览器/客户端/移动端支持单聊/群聊/组聊等功能支持永久保存聊天记录基于Server PUSH的即时内容更新,登录/登出/状态变更/消息等会内容即时更新支持发送连接/图片/语音/视频/文件(开发中)支持Web端直接管理所有在线用户和群组(开发中)内容来自www.zgxue.com请勿采集。


  • 本文相关:
  • php基于swoole多进程操作示例
  • php异步多线程swoole用法实例
  • php的swoole扩展安装方法详细教程
  • 详解thinkphp5+swoole实现异步邮件群发(smtp方式)
  • 在php 7下安装swoole与yar,yaf的方法教程
  • php扩展swoole实现实时异步任务队列示例
  • php+swoole+linux实现系统监控和性能优化操作示例
  • php swoole和redis异步任务实现方法分析
  • php swoole多进程/多线程用法示例【基于php7nts版】
  • laravel框架在本地虚拟机快速安装的方法详解
  • codeigniter框架过滤html危险代码
  • php读取和保存base64编码的图片内容
  • windows iis php 5.2 安装与配置方法
  • codeigniter框架验证码类库文件与用法示例
  • yii去掉必填项中星号的方法
  • 利用laravel+ajax实现文件上传功能方法示例
  • thinkphp5框架路由原理与用法详解
  • 基于ci(codeigniter)框架实现购物车功能的方法
  • 百度地图api应用之获取用户的具体位置
  • 请教各位用过PHP+Swoole实现的PHPWebIM的大神们,这个东西使用啊!
  • php swoole 只能运行在php-cli 环境吗
  • php中的swoole和workman比较。哪个socket长连接性能高
  • 如何简单通俗的理解 PHP 里的 swoole的websocket
  • Swoole和PHP到底什么关系~呢?
  • PHP如何利用SWOOLE扩展实现定时同步例子
  • 有用过swoole框架的同学进来说下吗
  • web前后端swoole怎么实现
  • PHP如何利用SWOOLE扩展实现定时同步例子分享
  • php swoole on receive里头的数据怎么返回
  • 网站首页网页制作脚本下载服务器操作系统网站运营平面设计媒体动画电脑基础硬件教程网络安全php基础php技巧php实例php文摘php模板首页php编程php实例php基于swoole多进程操作示例php异步多线程swoole用法实例php的swoole扩展安装方法详细教程详解thinkphp5+swoole实现异步邮件群发(smtp方式)在php 7下安装swoole与yar,yaf的方法教程php扩展swoole实现实时异步任务队列示例php+swoole+linux实现系统监控和性能优化操作示例php swoole和redis异步任务实现方法分析php swoole多进程/多线程用法示例【基于php7nts版】laravel框架在本地虚拟机快速安装的方法详解codeigniter框架过滤html危险代码php读取和保存base64编码的图片内容windows iis php 5.2 安装与配置方法codeigniter框架验证码类库文件与用法示例yii去掉必填项中星号的方法利用laravel+ajax实现文件上传功能方法示例thinkphp5框架路由原理与用法详解基于ci(codeigniter)框架实现购物车功能的方法百度地图api应用之获取用户的具体位置php获取数组长度的方法(有实例)微信公众平台实现获取用户openid教你如何使用php session使用php生成二维码的两种方法(带php发送get、post请求的6种方法简php中把stdclass object转array的微信公众平台网页授权获取用户基laravel框架数据库curd操作、连贯php字符串的连接的简单实例php删除数组中空值的方法介绍laravel 根据不同组织加载不同视图的实现laravel框架路由配置总结、设置技巧大全phpcms2008广告模板sql注入漏洞修复thinkphp框架实现定时执行任务的两种方法php生成缩略图填充白边(等比缩略图方案)php保留两位小数并且四舍五入及不四舍五入对laravel in 查询的使用方法详解form表单传递数组数据、php脚本接收的实例php文件缓存smarty模板应用实例分析zend framework教程之zend_controller_pl
    免责声明 - 关于我们 - 联系我们 - 广告联系 - 友情链接 - 帮助中心 - 频道导航
    Copyright © 2017 www.zgxue.com All Rights Reserved