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

什么是Actor?

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

Swoole协程与信箱

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

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";
      }
    });
  }
});

以上代码执行输出:

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • php安装swoole扩展的方法

    本文实例讲述了php安装swoole扩展的方法.分享给大家供大家参考.具体如下: 我本机是OS X,想要安装swoole体验一下,于是: 复制代码 代码如下: andy@AndyMacBookPro:/usr/local/webdata/github$ cd swoole-src/ andy@AndyMacBookPro:/usr/local/webdata/github/swoole-src$ git pull Already up-to-date. andy@AndyMacBookPro:/

  • PHP程序员学习使用Swoole的理由

    最近两个月一直在研究 Swoole,研究成果即将在6.21正式开源发布,这段时间没有来水文章,趁着今天放假来水水吧. 借助这篇文章,我希望能够把 Swoole 安利给更多人.虽然 Swoole 可能目前定位是一些高级 phper 的玩具,让中低级望而生畏,可能对一些应用场景也一脸懵逼,但其实没这么难的. 在 Swoole 官网的自我介绍是"面向生产环境的 PHP 异步网络通信引擎",首先 Swoole 它是一个网络应用的开发工具,它支持 Http.TCP.UDP.WebSocket.

  • PHP的swoole扩展安装方法详细教程

    Swoole支持PHP 5.3.10以上版本,所以安装Swoole之前请先安装PHP 5.3.10以上版本,现在来介绍Windows下PHP安装配置方法. 软件版本:php-5.3.1-Win32-VC6-x86.zip 这个不需要额外的安装.net的库,所以就用这个了.可以使用其他的. 1.PHP安装 使用绿色方式,下载Zip文件解压. 2.配置 在解压的根目录下找到php.ini-development,是用于开发环境的配置文件:还有一个php.ini-production,这个是用于生产环

  • 详解PHP swoole process的使用方法

    引入背景:假如我们每天有10000个订单生成,需要同步到仓储系统中去,以前做法是开启一个crontab去跑这些任务,但是发现总有感觉同步效率低,间隔时间都是分钟级别的. 解决方案测试:我们将同步订单的任务表添加一个hash作为key,作为分发条件,因为mysql中select如果做mod函数是用不到索引的,所以我们自己做随机hash,但是务必不需要范围太大,以免服务器资源不够,方法是根据hashkey投放到不同的进程中进行同步,测试代码如下 <?php /** * Created by PhpS

  • php异步多线程swoole用法实例

    本文实例讲述了php异步多线程swoole用法.分享给大家供大家参考.具体分析如下: swoole重新定义PHP语言的高性能网络通信框架,提供了PHP语言的异步多线程服务,下面的实例就可以证实这一功能. 一般来说,Swoole提供了PHP语言的异步多线程服务器,异步TCP/UDP网络客户端,异步MySQL,数据库连接池,AsyncTask,消息队列,毫秒定时器,异步文件读写,异步DNS查询. swoole以前听过, 拿来做游戏服务器简直是神器-今天稍微的感受了一下,  在 ubuntu 下搭建了

  • 初识PHP中的Swoole

    Swoole是一种PHP高级Web开发框架,框架不是为了提升网站的性能,是为了提升网站的开发效率.最少的性能损耗,换取最大的开发效率.利用Swoole框架,开发一个复杂的Web功能,可以在很短的时间内完成. 官方定义: Swoole:重新定义PHP PHP的异步.并行.高性能网络通信引擎,使用纯C语言编写,提供了PHP语言的异步多线程服务器,异步TCP/UDP网络客户端,异步MySQL,异步Redis,数据库连接池,AsyncTask,消息队列,毫秒定时器,异步文件读写,异步DNS查询. Swo

  • 使用php+swoole对client数据实时更新(一)

    如果想对一个列表做实时的更新,传统的做法是采用轮询的方式.以web为例,通过Ajax定时请求服务端然后获取数据显示在页面.这种方式实现简单,缺点就是浪费资源. HTTP1.1新增加了对websocket的支持,这样就可以将被动展示转变为主动通知.也就是通过websocket与服务端保持持久链接,一旦数据发生变化,由server通知client数据有更新,然后再进行刷新等操作.这样就省去了很多不必要的被动请求,节省了服务器资源. 要实现一个webscoket的程序,首先需要使用支持html5的浏览

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

    什么是Actor? Actor对于PHPer来说,可能会比较陌生,写过Java的同学会比较熟悉,Java一直都有线程的概念(虽然PHP有Pthread,但不普及),它是一种非共享内存的并发模型,每个Actor内的数据独立存在,Actor之间通过消息传递的形式进行交互调度,且Actor是一种高度抽象化的编程模型,非常适合于游戏.硬件行业. Swoole协程与信箱 得益于Swoole4.x,我们可以基于Swoole的协程与Channel快速实现一个信箱模式调度.模拟代码如下: use Swoole\

  • Go语言并发模型的2种编程方案

    概述 我一直在找一种好的方法来解释 go 语言的并发模型: 不要通过共享内存来通信,相反,应该通过通信来共享内存 但是没有发现一个好的解释来满足我下面的需求: 1.通过一个例子来说明最初的问题 2.提供一个共享内存的解决方案 3.提供一个通过通信的解决方案 这篇文章我就从这三个方面来做出解释. 读过这篇文章后你应该会了解通过通信来共享内存的模型,以及它和通过共享内存来通信的区别,你还将看到如何分别通过这两种模型来解决访问和修改共享资源的问题. 前提 设想一下我们要访问一个银行账号: 复制代码 代

  • 分析Go语言中CSP并发模型与Goroutine的基本使用

    目录 一.并发实现模型 1.1.多进程 1.2.多线程 1.3.协程 二.共享内存与CSP 三.Goroutine 一.并发实现模型 1.1.多进程 在之前的文章当中我们曾经介绍过,进程是操作系统资源分配的最小单元.所以多进程是在操作系统层面的并发模型,因为所有的进程都是有操作系统的内核管理的.所以每个进程之间是独立的,每一个进程都会有自己单独的内存空间以及上下文信息,一个进程挂了不会影响其他进程的运行.这个也是多进程最大的优点,但是它的缺点也很明显. 最大的缺点就是开销很大,创建.销毁进程的开

  • C#代替go采用的CSP并发模型实现

    目录 CSP(Communicating sequential processes) 在Go中的CSP 协程(提升并发的利器) 线程 线程的开销 回归协程 协程的目的 C#中的协程 C#中的CSP Go协程与.NET协程的区别? 写在最后 说起Golang(后面统称为Go),就想到他的高并发特性,在深入一些就是 Goroutine.在大家被它优雅的语法和简洁的代码实现的高并发程序所折服时,其实C#/.NET也可以很容易的做到.今天我们来参照Go,来用C#实现它所采用的的CSP并发模型. CSP(

  • CSP communicating sequential processes并发模型

    目录 前言 GO并发模型的实现原理 内核级线程模型 两级线程模型 Go线程实现模型MPG Goroutine 小结 优点: 缺点: 前言 https://www.jb51.net/article/228730.htm 请记住下面这句话: DO NOT COMMUNICATE BY SHARING MEMORY; INSTEAD, SHARE MEMORY BY COMMUNICATING. “不要以共享内存的方式来通信,相反,要通过通信来共享内存.” 普通的线程并发模型,就是像Java.C++.

  • Go语言CSP并发模型goroutine channel底层实现原理

    目录 Go的CSP并发模型(goroutine + channel) 1.goroutine goroutine的优点: 2.channel 无缓存channel 有缓存channel 3.Go并发模型的底层实现原理 4.一个CSP例子 参考Go的CSP并发模型实现:M, P, G Go语言是为并发而生的语言,Go语言是为数不多的在语言层面实现并发的语言. 并发(concurrency):多个任务在同一段时间内运行. 并行(parallellism):多个任务在同一时刻运行. Go的CSP并发模

  • Go语言CSP并发模型实现MPG

    目录 Golang调度机制 并发(concurrency)和并行(parallellism) Go的CSP并发模型 Go并发模型的实现原理 用户级线程模型 内核级线程模型 两级线程模型 Go线程实现模型MPG 抛弃P(Processor) 均衡的分配工作 Golang调度机制 最近抽空研究.整理了一下Golang调度机制,学习了其他大牛的文章.把自己的理解写下来.如有错误,请指正!!! golang的goroutine机制有点像线程池: 一.go 内部有三个对象: P对象(processor)

  • 示例剖析golang中的CSP并发模型

    目录 1. 相关概念: 2. CSP (通信顺序进程) 3. channel:同步&传递消息 4. goroutine:实际并发执行的实体 5. golang调度器 1. 相关概念: 用户态:当一个进程在执行用户自己的代码时处于用户运行态(用户态) 内核态:当一个进程因为系统调用陷入内核代码中执行时处于内核运行态(内核态),引入内核态防止用户态的程序随意的操作内核地址空间,具有一定的安全保护作用.这种保护模式是通过内存页表操作等机制,保证进程间的地址空间不会相互冲突,一个进程的操作不会修改另一个

  • Node.js 与并发模型的详细介绍

    目录 进程 线程 内核态线程 用户态线程 轻量级进程(LWP) 小结 协程 I/O 模型 阻塞 I/O 非阻塞 I/O 同(异)步 I/O Node.js 的并发模型 总结 前言: Node.js 现在已成为构建高并发网络应用服务工具箱中的一员,何以 Node.js 会成为大众的宠儿?本文将从进程.线程.协程.I/O 模型这些基本概念说起,为大家全面介绍关于 Node.js 与并发模型的这些事. 进程 我们一般将某个程序正在运行的实例称之为进程,它是操作系统进行资源分配和调度的一个基本单元,一般

  • Windows 下安装 swoole 图文教程(php)

    Windows 下安装 swoole 具体步骤: Swoole,原本不支持在Windows下安装的,所以我们要安装Cygwin来使用.在安装Cygwin下遇到了很多坑,百度经验上的文档不是很全,所以我把自己安装Cygwin和Swoole写下来相当于对自己的沉淀吧. 首先准备工具: Cygwin 官方地址:http://www.cygwin.com/ swoole 官方下载地址:https://github.com/swoole/swoole-src/releases 一.下载Swoole和Cyg

随机推荐