亚洲精品成人_精品成人一区_999视频在线播放_免费黄色在线_亚洲成人久久久_久久www免费视频

Actor

提供Actor模式支持,助力游戲行業(yè)開發(fā)。EasySwooleActor采用自定義Process作為存儲載體,以協(xié)程作為最小調度單位,利用協(xié)程Channelmail box,而客戶端與Process之間的通訊,采用UnixSocket實現(xiàn),并且借助TCP實現(xiàn)分布式的ActorClient,超高并發(fā)下也能輕松應對。

工作流程

一般來說有兩種策略用來在并發(fā)線程中進行通信:共享數(shù)據(jù)和消息傳遞。使用共享數(shù)據(jù)方式的并發(fā)編程面臨的最大的一個問題就是數(shù)據(jù)條件競爭,當兩個實例需要訪問同一個數(shù)據(jù)時,為了保證數(shù)據(jù)的一致性,通常需要為數(shù)據(jù)加鎖,而Actor模型采用消息傳遞機制來避免數(shù)據(jù)競爭,無需復雜的加鎖操作,各個實例只需要關注自身的狀態(tài)以及處理收到的消息。

Actor是完全面向對象、無鎖、異步、實例隔離、分布式的并發(fā)開發(fā)模式。Actor實例之間互相隔離,Actor實例擁有自己獨立的狀態(tài),各個Actor之間不能直接訪問對方的狀態(tài),需要通過消息投遞機制來通知對方改變狀態(tài)。由于每個實例的狀態(tài)是獨立的,沒有數(shù)據(jù)被共享,所以不會發(fā)生數(shù)據(jù)競爭,從而避免了并發(fā)下的加鎖問題。

舉一個游戲場景的例子,在一個游戲房間中,有5個玩家,每個玩家都是一個PlayerActor,擁有自己的屬性,比如角色ID,昵稱,當前血量,攻擊力等。游戲房間本身也是一個RoomActor,房間也擁有屬性,比如當前在線的玩家,當前場景的怪物數(shù)量,怪物血量等。此時玩家A攻擊某個怪物,則PlayerActor-ARoomActor發(fā)送一個攻擊怪物的指令,RoomActor經過計算,得出玩家A對怪物的傷害值,并給房間內的所有PlayerActor發(fā)送一個消息(玩家A攻擊怪物A,造成175點傷害,怪物A剩余血量1200點),類似此過程,每個PlayerActor都可以得知房間內發(fā)生了什么事情,但又不會造成同時訪問怪物A的屬性,導致的共享加鎖問題。

安裝

Actor并沒有作為內置組件,需要先引入包并進行基礎配置才能夠使用。

composer require easyswoole/actor

使用

建立一個Actor

每一種對象(玩家、房間、甚至是日志服務也可以作為一種Actor對象)都建立一個Actor來進行管理,一個對象可以擁有多個實例(Client)并且可以互相通過信箱發(fā)送消息來處理業(yè)務。

<?php

namespace App\Player;

use EasySwoole\Actor\AbstractActor;
use EasySwoole\Actor\ActorConfig;

/**
 * 玩家Actor
 * Class PlayerActor
 * @package App\Player
 */
class PlayerActor extends AbstractActor
{
    /**
     * 配置當前的Actor
     * @param ActorConfig $actorConfig
     */
    public static function configure(ActorConfig $actorConfig)
    {
        $actorConfig->setActorName('PlayerActor');
        $actorConfig->setWorkerNum(3);
    }

    /**
     * Actor首次啟動時
     */
    protected function onStart()
    {
        $actorId = $this->actorId();
        echo "Player Actor {$actorId} onStart\n";
    }

    /**
     * Actor收到消息時
     * @param $msg
     */
    protected function onMessage($msg)
    {
        $actorId = $this->actorId();
        echo "Player Actor {$actorId} onMessage\n";
    }

    /**
     * Actor即將退出前
     * @param $arg
     */
    protected function onExit($arg)
    {
        $actorId = $this->actorId();
        echo "Player Actor {$actorId} onExit\n";
    }

    /**
     * Actor發(fā)生異常時
     * @param \Throwable $throwable
     */
    protected function onException(\Throwable $throwable)
    {
        $actorId = $this->actorId();
        echo "Player Actor {$actorId} onException\n";
    }

}

注冊Actor服務

可以使用setListenAddresssetListenPort指定本機對外監(jiān)聽的端口,其他機器可以通過該端口向本機的Actor發(fā)送消息。


public static function mainServerCreate(EventRegister $register) {

    // 注冊Actor管理器
    $server = \EasySwoole\EasySwoole\ServerManager::getInstance()->getSwooleServer();
    \EasySwoole\Actor\Actor::getInstance()->register(PlayerActor::class);
    \EasySwoole\Actor\Actor::getInstance()->setTempDir(EASYSWOOLE_TEMP_DIR)
        ->setListenAddress('0.0.0.0')->setListenPort('9900')->attachServer($server);

}

Actor實例管理

服務啟動后就可以進行Actor的操作,管理本機的Client實例,則不需要給client傳入$node參數(shù),默認的node為本機,管理其他機器時需要傳入。


    // 管理本機的Actor則不需要聲明節(jié)點
    $node = new \EasySwoole\Actor\ActorNode();
    $node->setIp('127.0.0.1');
    $node->setListenPort(9900);

    // 啟動一個Actor并得到ActorId 后續(xù)操作需要依賴ActorId
    $actorId = PlayerActor::client($node)->create(['time' => time()]);   // 00101000000000000000001
    // 給某個Actor發(fā)消息
    PlayerActor::client($node)->send($actorId, ['data' => 'data']);
    // 給該類型的全部Actor發(fā)消息
    PlayerActor::client($node)->sendAll(['data' => 'data']);
    // 退出某個Actor
    PlayerActor::client($node)->exit($actorId, ['arg' => 'arg']);
    // 退出全部Actor
    PlayerActor::client($node)->exitAll(['arg' => 'arg']);

架構解讀

Actor

應該叫ActorManager更確切點,它用來注冊Actor啟動ProxyActorWorker進程。

當你在業(yè)務邏輯里定義了幾種Actor,比如RoomActor、PlayerActor,需要在SwooleServer啟動時注冊它們。

具體就是在EasySwooleEvent.mainServerCreate方法中添加如下代碼。

$actor = Actor::getInstance();
$actor->register(RoomActor::class);
$actor->register(PlayerActor::class);
$actorConf = Config::getInstance()->getConf('ACTOR_SERVER');
$actor->setMachineId($actorConf['MACHINE_ID'])
    ->setListenAddress($actorConf['LISTEN_ADDRESS'])
    ->setListenPort($actorConf['PORT'])
    ->attachServer($server);

其中ListenAddress、ListenPortProxy進程的監(jiān)聽地址端口,MachineIdActorWorker進程的機器碼。

MachineIdIP:PORT對應。

attachServer將開啟相應數(shù)量的Proxy進程,以及前邊registerActorWorker進程。

工作原理

Proxy進程做消息中轉,Worker進程做消息分發(fā)推送。來看個具體的例子:

游戲中玩家P請求進入房間R,抽象成Actor模型就是PlayerActor需要往RoomActor發(fā)送請求加入的命令。

那么這時候需要這樣寫:

\EasySwoole\Actor\Test\RoomActor::client($node)->send($roomActorId, [
    'user_actor_id' => $userActorId,
    'data'  => '其他進入房間的參數(shù)'
])

其中$roomActorId$userActorId是事先xxActor::client()->create()出來的。

上面那段代碼的意思就是往$roomActorIdRoomActor實例推送了一條$userActorId玩家的UserActor實例要加入房間的消息。

參數(shù)$node用來尋址Proxy,它由目標Actor實例的Worker.MachineId決定,在本例中就是$roomActorId被創(chuàng)建在了哪個MachineIdWorkerProcess

通過$roomActorId中的機器碼找到IP:PORT,生成$node。

send時會創(chuàng)建一個協(xié)程TcpClient,將消息發(fā)送給Proxy,然后Proxy將消息轉發(fā)(UnixClient)至本機WorkerProcessWorkerProcess收到消息,推送到具體的Actor實例。

這樣就完成了從PlayerActorRoomActor的請求通訊,RoomActor收到請求消息并處理完成后,向PlayerActor回發(fā)處理結果,用的是同樣的通訊流程。

如果是單機部署,可以忽略$node參數(shù),因為所有通訊都是在本機進行。

多機的話,需要自己根據(jù)業(yè)務來實現(xiàn)Actor如何分布和定位。

主要屬性

machineId 機器碼

proxyNum 啟動幾個ProxyProcess

listenPort 監(jiān)聽port

listenAddress 監(jiān)聽ip

AbstractActor

Actor實例的基類,所有業(yè)務中用到的Actor都將繼承于`AbstractActor。例如游戲場景中的房間,你可以:

class RoomActor extends AbstractActor

工作原理

每個Actor實例都維護一份獨立的數(shù)據(jù)和狀態(tài),當一個Actor實例通過client()->create()后,會開啟協(xié)程循環(huán),接收mailbox pop的消息,進而處理業(yè)務邏輯,更新自己的數(shù)據(jù)及狀態(tài)。具體實現(xiàn)就是__run()這個方法。

靜態(tài)方法 configure

用來配置ActorConfig,只需要在具體的Actor(如RoomActor)去重寫這個方法就行。

關于ActorConfig具體屬性可以看下邊ActorConfig部分。

幾個虛擬方法

以下幾個虛擬方法需要在Actor子類中實現(xiàn),這幾個方法被用在__run()中來完成Actor的運行周期。

onStart() 在協(xié)程開啟前執(zhí)行,你可以在此進行Actor初始化的一些操作,比如獲取房間的基礎屬性等。

onMessage() 當接收到消息時執(zhí)行,一個Actor實例的生命周期基本上就是在收消息-處理-發(fā)消息,你需要在這里對消息進行解析處理。

onExit() 當接收到退出命令時執(zhí)行。比如你希望在一個Actor實例退出的時候,同時通知某些關聯(lián)的其他Actor,可以在此處理。

其它

exit() 用于實例自己退出操作,會向自己發(fā)一條退出的命令。

tick()、after() 兩個定時器,用于Actor實例的定時任務,比如游戲房間的定時刷怪(tick);掉線后多長時間自動踢出(after)。

static client() 用于創(chuàng)建一個ActorClient來進行對應Actor(實例)的通訊。

ActorClient

Actor通訊客戶端,調用xxActor::client()來創(chuàng)建一個ActorClient進行Actor通訊。

上邊已經大概講過了Actor的通訊流程,本質就是TcpClient->ProxyProcess->UnixClient->ActorWorkerProcess->xxActor。

看下它實現(xiàn)了哪些方法:

create() 創(chuàng)建一個xxActor實例,返回actorId,在之后你可以使用這個actorId與此實例進行通訊。

send() 指定actorId,向其發(fā)送消息。

exit() 通知xxActor退出指定actorId的實例。

sendAll() 向所有的xxActor實例發(fā)送消息。

exitAll() 退出所有xxActor實例。

exist() 當前是否存在指定actorIdxxActor實例。

status() 當前ActorWorkerxxActor的分布狀態(tài)。

ActorConfig

具體Actor的配置項,比如RoomActor、PlayerActor都有自己的配置。

actorName 一般用類名就可以,注意在同一個服務中這個是不能重復的。

actorClassActor->register()會將對應的類名寫入。

workerNumActor開啟幾個進程,Actor->attachServer()時會根據(jù)這個參數(shù)為相應Actor啟動WorkerNumWorker進程。

ActorNode

上邊提到過,xxActor::client($node),這個$node就是ActorNode對象,屬性為IpPort,用于尋址Proxy。

WorkerConfig

WorkerProcess的配置項,WorkerProcess啟動時用到。

workerId worker進程Id,create Actor的時候用于生成actorId

machineId worker進程機器碼,create Actor的時候用于生成actorId

trigger 異常觸發(fā)處理接口

WorkerProcess

Actor的重點在這里,每個注冊的Actor(類)會啟動相應數(shù)量的WorkerProcess。

比如你注冊了RoomActor、PlayerActor,workerNum都配置的是3,那么系統(tǒng)將啟動3個RoomActorWorker進程和3個PlayerActorWorker進程。

每個WorkerProcess維護一個ActorList,你通過client()->create()Actor將分布在不同Worker進程里,由它的ActorList進行管理。

WorkerProcess通過協(xié)程接收client(這個client就是Proxy做轉發(fā)時的UnixClient)消息,區(qū)分消息類型,然后分發(fā)給對應的Actor實例。

請仔細閱讀下WorkerProcess的源碼,它繼承于AbstractUnixProcess

UnixClient

UnixStream Socket,自行了解。Proxy轉發(fā)消息給本機Actor所使用的Client。

Protocol

數(shù)據(jù)封包協(xié)議。

ProxyCommand

消息命令對象,Actor2將不同類型的消息封裝成格式化的命令,最終傳給WorkerProcess

你可以在ActorClient中了解一下方法和命令的對應關系,但這個不需要在業(yè)務層去更改。

ProxyConfig

消息代理的配置項。

actorList 注冊的actor列表。

machineId 機器碼

tempDir 臨時目錄

trigger 錯誤觸發(fā)處理接口

ProxyProcess

Actor->attachServer()會啟動proxyNumProxyProcess。

用于在Actor實例和WorkerProcess做消息中轉。

亚洲精品成人_精品成人一区_999视频在线播放_免费黄色在线_亚洲成人久久久_久久www免费视频
  • <kbd id="eqi2k"><code id="eqi2k"></code></kbd><cite id="eqi2k"><tbody id="eqi2k"></tbody></cite>
    国产精品一区二区欧美黑人喷潮水| 欧美三级不卡| 国产精品9999久久久久仙踪林| 性伦欧美刺激片在线观看| 欧美亚洲一级| 黄色99视频| 亚洲一区二区四区| 日韩视频久久| 国产超碰91| 亚洲人成网站在线观看播放 | 欧美日韩一区二区视频在线观看| 麻豆成人av| 精品一区二区国产| 日本不卡免费新一二三区| 欧美福利在线| 999热视频| 中文字幕久久一区| 91中文字精品一区二区| 亚洲欧洲久久| 91久久久一线二线三线品牌| 涩涩涩999| 性欧美长视频| 亚洲欧洲三级| 7777精品久久久大香线蕉小说| 欧美日韩精品综合| 国产乱码精品| 亚洲午夜精品福利| 91网免费观看| 精品999在线观看| 久久久久一区二区| 亚洲在线观看| 欧美日韩另类丝袜其他| 国产乱码精品一区二区三区日韩精品| 欧美日本不卡高清| 精品伦精品一区二区三区视频| 亚洲激情成人| 亚洲午夜精品久久久中文影院av| 久久夜色精品| 日韩午夜电影| 综合操久久久| 日韩欧美99| 国产日韩欧美二区| 老鸭窝91久久精品色噜噜导演| 亚洲一区三区电影在线观看| 国产欧美一区二区三区不卡高清| 亚洲国产专区| 国产精品av久久久久久麻豆网| 麻豆av一区| 福利精品视频| 国产精品一区视频网站| 中文字幕欧美日韩一区二区三区| 精品国产91亚洲一区二区三区www| 亚洲一区二区动漫| 99精品久久久| 99精品国产福利在线观看免费| 在线看成人av电影| 四虎影院一区二区三区| 欧美午夜精品久久久久免费视| 99久久一区三区四区免费| 国产精品久久久亚洲一区| 亚洲精品视频一区二区三区 | 99pao成人国产永久免费视频| 亚洲免费视频一区| 日韩欧美三级一区二区| 久久久久久a亚洲欧洲aⅴ| 国产精品白丝jk白祙| 99视频网站| 国产精品视频免费一区| 国产不卡一区二区在线观看| 4444kk亚洲人成电影在线| 久久日韩精品| 国产99午夜精品一区二区三区| 久久婷婷av| 国产精品三区四区| 久久久久一区二区| 麻豆亚洲一区| 亚洲精品乱码视频| 欧美伊人影院| 国产精品二区影院| 中文精品视频一区二区在线观看| 国产日韩三区| 肥熟一91porny丨九色丨| 国产在线精品一区二区中文 | 国产99午夜精品一区二区三区| 99国产精品久久久久老师| 国产精品久久久久久久免费大片| 国产一区二区在线网站| 日本精品视频一区| 欧美精选在线| 亚洲中字在线| 国产在线精品日韩| 亚洲mv在线看| 日韩亚洲视频在线| 国产精品theporn88| 欧美精品一区二区三区在线四季| 亚洲国产精品久久久久婷婷老年| 午夜日韩福利| 久久九九99| 欧美一区二区三区四区五区六区 | 97久久精品午夜一区二区| 国产伦精品一区二区三区视频黑人 | 亚洲精品一区二区三区蜜桃久| 欧美一区二区三区另类| 在线国产精品一区| 国产精品免费一区二区三区| 婷婷亚洲婷婷综合色香五月| 亚洲午夜一级| 激情小说网站亚洲综合网| 亚洲欧美日韩在线综合| 国产欧美日韩一区| 欧美激情专区| 亚洲一区欧美二区| 日本欧美色综合网站免费| 亚洲美女91| 欧美日韩一区二区视频在线| 亚洲性图久久| 激情视频在线观看一区二区三区| 欧美日韩国产三区| 国产麻豆一区二区三区在线观看| 在线成人性视频| 久久一日本道色综合久久| 亚洲精品视频一区二区三区| 久久久久久自在自线| 中文字幕日韩一区二区三区不卡| 久久久久久色| 国内精品久久久久久久果冻传媒| 国产精品初高中精品久久| 好吊日精品视频| 欧美激情第六页| 久久国产精品久久精品国产| 亚洲国产日韩欧美| 国产精品日韩一区二区| 亚洲人体偷拍| 亚洲精品自在在线观看| 国产一级精品aaaaa看| 亚洲国产精品www| 亚洲在线视频一区二区| 极品校花啪啪激情久久| 久久精品电影| 亚洲精品黄色| 欧美日韩一区二区三区四区在线观看| 国产精品日本一区二区| 亚洲一区日本| 亚洲精品1区| 欧美日韩亚洲一区三区| 精品国产综合久久| 超碰97在线资源| 香蕉成人久久| 一区二区精品在线| 亚洲午夜精品一区二区| 亚洲成人网上| 日本精品二区| 欧美久久在线| 蜜桃91精品入口| 国产亚洲自拍偷拍| av资源站久久亚洲| 久久精品成人一区二区三区蜜臀| 在线成人欧美| 国产精品地址| 欧美日韩一区二区三区免费| 欧美在线一二三区| 一区二区精品免费视频| 神马影院午夜我不卡影院| 欧美日韩大片一区二区三区| 好吊色欧美一区二区三区四区 | 日本亚洲欧洲精品| 国产一区二区三区四区五区在线 | 狠狠色综合色区| 欧美一区免费| 欧美日韩专区| 欧美精品国产| 欧美精品一卡| 伊人久久大香线蕉综合热线| 亚洲先锋成人| 国产日韩亚洲| 51国偷自产一区二区三区的来源| 97netav| 国产精品一区二区不卡视频| 久久精品日产第一区二区三区乱码 | 欧美综合二区| 久久天堂精品| 国内外成人免费视频| 免费在线成人av| 椎名由奈jux491在线播放 | 久久久久99| 99在线热播| 久久精品中文字幕一区二区三区 | 欧美一区二区在线| 国产在线一区二区三区四区 | 日韩黄色影视| 午夜久久久久| 亚洲永久视频| av观看久久| 亚洲欧洲精品一区二区| 在线播放日韩| 国产精品成人观看视频免费| 人偷久久久久久久偷女厕| 午夜精品影院| 99久久一区三区四区免费| 日本在线观看一区二区三区|