当前位置: 首页 > 后端技术 > PHP

Actor并发模型

时间:2023-03-30 02:44:38 PHP

是PHP下用Swoole实现的什么是Actor?Actor对于PHPer来说可能比较陌生,写过Java的同学会比较熟悉。Java一直有线程的概念(PHP虽然有Pthreads,但并不流行),它是一种非共享内存的并发模型,每个Actor中的数据都是独立存在的,Actor之间以消息的形式交互调度通过,Actor是一种高度抽象的编程模型,非常适合游戏和硬件行业。Swoole协程和邮箱得益于Swoole4.x,我们可以快速实现一个基于Swoole协程和Channel的邮箱模式调度。模拟代码如下:useSwoole\Coroutine\Channel;go(function(){//创建十个邮箱通道$mailBoxes=[];for($i=1;$i<=10;$i++){$mailBoxes[$i]=newChannel(16);}//模拟主邮局调度,像邮箱一样随机投递邮件go(function()use($mailBoxes){while(1){\co::sleep(2);$key=rand(1,10);($mailBoxes[$key])->push(time());}});//模拟actor实体消费为($i=1;$i<=10;$i++){go(function()use($mailBoxes,$i){while(1){$msg=($mailBoxes[$i])->pop();echo"Actor{$i}recv味精:{$味精}\n";}});}});上面代码执行输出:phptest.phpActor8recvmsg:1559622691Actor10recvmsg:1559622693Actor1recvmsg:1559622695Actor5recvmsg:1559622697Coroutine每次通道遇到POP没有数据的时候会自动放弃执行权(详见Swoole协程调度)Actor库基于以上原理,我们实现了一个多进程分布式协程Actor库composerrequireeasyswoole/actor=2.x-dev我们依赖dev用于测试的库,生产可以依赖稳定的版本过程关系。在Easyswoole的Actor模型中,有两组进程,一组是代理进程,用于实现Actor对外提供服务,一组是worker进程,proxy进程通过unixsock与worker进程通信,Actor实例均匀分布在worker中。例如,在聊天室中,我们可以定义一个房间模型。命名空间EasySwoole\Actor\Test;使用EasySwoole\Actor\AbstractActor;使用EasySwoole\Actor\ActorConfig;classRoomActorextendsAbstractActor{publicstaticfunctionconfigure(ActorConfig$actorConfig){$actorConfig->setActorName('Room');}publicfunctiononStart(){//每当创建RoomActor实体时,都会执行回调var_dump('roomactor'.$this->actorId().'start');}publicfunctiononMessage($msg){//每当RoomActor实体接收到外部消息时,会执行回调var_dump('roomactor'.$this->actorId().'onmessage:'.$msg);return'replyat'.time();}publicfunctiononExit($arg){//每当RoomActor实体退出时,回调将被执行var_dump('roomactor'.$this->actorId().'exitatarg:'.$arg);return'exitat'.time();}protectedfunctiononException(\Throwable$throwable){//每当一个RoomActor出现异常时,就会执行回调var_dump($throwable->getMessage());在cli模式下使用EasySwool创建Actor服务e\Actor\Actor;使用EasySwoole\Actor\Test\RoomActor;使用EasySwoole\Actor\ProxyProcess;Actor::getInstance()->register(RoomActor::class);$list=Actor::getInstance()->generateProcess();foreach($list['proxy']as$proxy){/**@varProxyProcess$proxy*/$proxy->getProcess()->start();}foreach($list['worker']作为$actors){foreach($actorsas$actorProcess){/**@varProxyProcess$actorProcess*/$actorProcess->getProcess()->start();}}while($ret=\Swoole\Process::wait()){echo"PID={$ret['pid']}\n";}创建一个cli测试脚本useEasySwoole\Actor\Actor;useEasySwoole\Actor\Test\RoomActor;Actor::getInstance()->register(RoomActor::class);go(function(){$actorId=RoomActor::client()->create('createarg1');var_dump($actorId);\co::sleep(3);var_dump(RoomActor::client()->send($actorId,'thisismsg'));\co::sleep(3);var_dump(RoomActor::client()->exit($actorId,'这是退出参数'));\co::sleep(3);RoomActor::client()->create('createarg2');\co::睡眠(3);RoomActor::client()->create('createarg3');\co::睡眠(3);var_dump(RoomActor::client()->sendAll('sendAllmsg'));\co::睡眠(3);var_dump(RoomActor::client()->status());\co::睡眠(3);var_dump(RoomActor::client()->exitAll('sendAllexit'));});以上代码执行结果如下:服务端phptest.phpstring(40)"roomactor001010000000000000000000000000000001start"string(57)"room演员001010000000000000000000001onmessage:这是MSG“字符串(64)”房间演员00101000000000000000000000001退出ARG:这是ExitArgarg'String(40)“室演员00101000000000000000000000002房间演员0010100000000000000000002onMessage:SendallMsg“String(57)”房间演员00103000000000000000000000000000001onMessage:SendallMsg“string(60)”室演员0010100000000000000002ndAllexit"clientphptest2.phpstring(23)"00101000000000000000001"string(19)"replyat1559623925"string(18)"exitat1559623928"bool(true)array(3){[1]=>int(1)[2]=>int(0)[3]=>int(1)}bool(true)更详细的可以去EasySwoole项目官网http://easyswoole.com/获取文档支持如果喜欢EasySwoole项目,可以给个starhttps://github.com/easy-swool...

猜你喜欢