亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

PHP物聯(lián)網(wǎng)開發(fā)利器之Actor并發(fā)模型

ixlei / 2487人閱讀

摘要:然而盡管如此,很多人可能都沒(méi)有思考過(guò),如何優(yōu)雅的寫出自己的物聯(lián)網(wǎng)服務(wù)器。

PHP不適合做物聯(lián)網(wǎng)服務(wù)端嗎?

在傳統(tǒng)的思維中,經(jīng)常會(huì)有人告訴你,php不適合用來(lái)做物聯(lián)網(wǎng)服務(wù)端,讓你換java,node,go等其他語(yǔ)言,是的,沒(méi)錯(cuò)傳統(tǒng)意義上的php,確實(shí)很難做物聯(lián)網(wǎng)服務(wù)器,因?yàn)樗鼘?shí)在太蹩腳了,當(dāng)然,這也不是意味著徹底就不能做。舉個(gè)例子,當(dāng)你想實(shí)現(xiàn)一個(gè)TCP服務(wù)器的時(shí)候,你可能需要寫出原理大約如下的代碼:

for ($i = 0;$i <= 1;$i++){
    $pid = pcntl_fork();
    if($pid){
        if($i == 0){
            $server = stream_socket_server("tcp://127.0.0.1:9501", $errno, $errstr, STREAM_SERVER_BIND);
        }else if($i == 1){
            $tickTime = time()+3600;
            while (1){
                usleep(1);
                if($tickTime == time()){
                    //do my tick func
                }
            }
        }
    }
}

以上代碼的意義等于在一個(gè)進(jìn)程中創(chuàng)建一個(gè)TCP 服務(wù)端,另外一個(gè)進(jìn)程中死循環(huán)來(lái)做時(shí)間檢測(cè),從而實(shí)現(xiàn)定時(shí)器邏輯。這樣看起來(lái),確實(shí)很蹩腳,而且對(duì)于編程基礎(chǔ)普遍比較薄弱的PHPer來(lái)說(shuō),這真的很難維護(hù)。當(dāng)然這個(gè)時(shí)候,就會(huì)有人說(shuō),這不是還有Workerman嗎,是的,確實(shí)還有Workerman,Workerman就是高度封裝了上述代碼原理,幫助你專心于實(shí)現(xiàn)代碼邏輯的一個(gè)PHP多進(jìn)程框架,因此說(shuō)PHP不時(shí)候做物聯(lián)網(wǎng),其實(shí)這是謬論。當(dāng)然這個(gè)時(shí)候可能又會(huì)有人說(shuō),go語(yǔ)言有協(xié)程,你用Workerman當(dāng)出現(xiàn)阻塞數(shù)據(jù)庫(kù)調(diào)用的時(shí)候,那效率就非常的差,很難出現(xiàn)高并發(fā),這么說(shuō)沒(méi)錯(cuò),但是實(shí)際上,我們可以盡可能的用多進(jìn)程去彌補(bǔ)這個(gè)不足,也就是堆機(jī)器。當(dāng)然,如果你真的想錙銖必較,沒(méi)關(guān)系,這個(gè)時(shí)候我們就可以拿出我們的殺器,那就是Swoole4.x的協(xié)程。

Swoole做TCP服務(wù)器

舉個(gè)例子,如下代碼:

$server = new swoole_server("127.0.0.1", 9501);
$server->on("workerstart",function ($ser,$workerId){
    if($workerId == 0){
        swoole_timer_tick(1000,function (){
            
        });
    }
});
$server->on("connect", function ($server, $fd){
    echo "connection open: {$fd}
";
});
$server->on("receive", function ($server, $fd, $reactor_id, $data) {
    $server->send($fd, "Swoole: {$data}");
    $server->close($fd);
});
$server->on("close", function ($server, $fd) {
    echo "connection close: {$fd}
";
});
$server->start();

我們就可以很快的創(chuàng)建出一個(gè)多進(jìn)程的協(xié)程TCP服務(wù)器,而且在各個(gè)回調(diào)函數(shù)內(nèi),均自動(dòng)創(chuàng)建協(xié)程環(huán)境,我們可以在協(xié)程回調(diào)內(nèi),去調(diào)用協(xié)程的數(shù)據(jù)庫(kù)API,這樣就避免了因?yàn)樽枞麛?shù)據(jù)庫(kù)調(diào)用而導(dǎo)致無(wú)法處理其他客戶端請(qǐng)求的問(wèn)題。然而盡管如此,很多人可能都沒(méi)有思考過(guò),如何優(yōu)雅的寫出自己的物聯(lián)網(wǎng)服務(wù)器。舉個(gè)例子,我們常見(jiàn)的互聯(lián)網(wǎng)設(shè)備管理服務(wù)中,大約可能出現(xiàn)如下代碼:

swoole_timer_tick(5000,function (){
    $deviceList = $db->getAll();
    foreach ($deviceList as $device){
        //do your check
        /*
         * 例如設(shè)備狀態(tài)處于1,那么需要處理流程1
         * 例如設(shè)備狀態(tài)處于2,那么需要處理流程2
         * 例如設(shè)備狀態(tài)處于3,那么需要處理流程3
         */
    }
});
定時(shí)遍歷檢查設(shè)備狀態(tài)以及廣播
這樣乍一看好像無(wú)傷大雅,但是當(dāng)出現(xiàn)多種設(shè)備,且每種設(shè)備邏輯都不一致的時(shí)候,那么這樣的編寫模式就很容易寫出一大坨代碼出來(lái),而且在協(xié)程下,如果不注意變量訪問(wèn)安全與協(xié)程上下文隔離,那么就很容易出現(xiàn)bug,導(dǎo)致很難維護(hù)。
Actor模型

什么是Actor,簡(jiǎn)單來(lái)說(shuō),Actor就是一種高度抽象化的并發(fā)模型,每個(gè)Actor實(shí)例的內(nèi)存空間都是互相隔離的,用于降低用戶編程與維護(hù)難度。關(guān)于Swoole4.x如何實(shí)現(xiàn)協(xié)程版本的Actor,我們之前已經(jīng)在文章 https://segmentfault.com/a/11... 中講解了如何用Swoole實(shí)現(xiàn)協(xié)程的原理。

Actor模型庫(kù)實(shí)戰(zhàn)

我們依舊用easyswoole/actor庫(kù)來(lái)講解,例如,我們有一種型號(hào)的設(shè)備,那么我們可以定義一個(gè)設(shè)備Actor,并把該設(shè)備的全部邏輯,寫在該actor模型內(nèi),例子代碼如下:

namespace AppDevice;


use EasySwooleActorAbstractActor;
use EasySwooleActorActorConfig;
use EasySwooleEasySwooleLogger;
use EasySwooleEasySwooleServerManager;
use EasySwooleEasySwooleTrigger;

class DeviceActor extends AbstractActor
{
    private $fd;
    private $deviceId;
    private $lastHeartBeat;
    public static function configure(ActorConfig $actorConfig)
    {
       $actorConfig->setActorName("Device");
    }

    protected function onStart()
    {
        $this->lastHeartBeat = time();
        /*
         * 該參數(shù)是創(chuàng)建的時(shí)候傳遞的
         */
        $this->fd = $this->getArg()["fd"];
        $this->deviceId = $this->getArg()["deviceId"];
        //記錄到table manager中
        DeviceManager::addDevice(new DeviceBean([
            "deviceId"=>$this->deviceId,
            "actorId"=>$this->actorId(),
            "fd"=>$this->fd
        ]));
        //推送消息
        ServerManager::getInstance()->getSwooleServer()->push($this->fd,"connect to server success,your actorId is {$this->actorId()}");
        //創(chuàng)建一個(gè)定時(shí)器,如果一個(gè)設(shè)備20s沒(méi)有收到消息,自動(dòng)下線
        $this->tick(20*2000,function (){
            if(time() - $this->lastHeartBeat > 20){
                $this->exit(-1);
            }
        });
    }

    protected function onMessage($msg)
    {
        if($msg instanceof Command){
            switch ($msg->getCommand()){
                case $msg::RECONNECT:{
                    DeviceManager::updateDeviceInfo($this->deviceId,[
                        "fd"=>$msg->getArg()
                    ]);
                    $this->fd = $msg->getArg();
                    Logger::getInstance()->console("deviceId {$this->deviceId}  at actorId {$this->actorId()} reconnect success");
                    ServerManager::getInstance()->getSwooleServer()->push($this->fd,"deviceId {$this->deviceId}  at actorId {$this->actorId()} reconnect success");
                    break;
                }
                case $msg::WS_MSG:{
                    $recv = $msg->getArg();
                    Logger::getInstance()->console("deviceId {$this->deviceId}  at actorId {$this->actorId()} recv ws msg: {$recv}");
                    ServerManager::getInstance()->getSwooleServer()->push($this->fd,"actor recv msg for hash ".md5($recv));
                    break;
                }
                case $msg::REPLY_MSG:{
                    $recv = $msg->getArg();
                    Logger::getInstance()->console("deviceId {$this->deviceId}  at actorId {$this->actorId()} recv reply msg: {$recv}");
                    ServerManager::getInstance()->getSwooleServer()->push($this->fd,"actor recv reply msg ".$recv);
                    //此處return 一個(gè)數(shù)據(jù),會(huì)返回給客戶端
                    return "actorId {$this->actorId()} recv {$recv}";
                    break;
                }
            }
        }
    }

    protected function onExit($arg)
    {
        if($arg == -1){
            if(ServerManager::getInstance()->getSwooleServer()->exist($this->fd)){
                ServerManager::getInstance()->getSwooleServer()->push($this->fd,"heartbeat lost,actor exit");
                ServerManager::getInstance()->getSwooleServer()->close($this->fd);
            }
        }
        DeviceManager::deleteDevice($this->deviceId);
        Logger::getInstance()->console("deviceId {$this->deviceId} at actorId {$this->actorId()} exit");
    }

    protected function onException(Throwable $throwable)
    {
        Trigger::getInstance()->throwable($throwable);
    }
}

在該Actor內(nèi),我們定義了這個(gè)設(shè)備的生命周期行為。

設(shè)備上線,記錄設(shè)備id與fd信息,并創(chuàng)建心跳周期檢查

收到消息,可以對(duì)該Actor投遞數(shù)據(jù),處理對(duì)應(yīng)的消息行為

設(shè)備下線,當(dāng)設(shè)備下線,可以自動(dòng)的清理定時(shí)器與其他的一些通知與清理邏輯

我們可以很清楚的看到,Actor模型下,允許我們對(duì)一種設(shè)備模型進(jìn)行高度自治的管理。當(dāng)然,我們本章節(jié)主要在講解如何優(yōu)雅的利用Swoole協(xié)程來(lái)實(shí)現(xiàn)Actor模型,從而更好的開發(fā)管理我們的設(shè)備,因此我不再貼過(guò)多的代碼,有興趣的同學(xué)可以在Easyswoole框架demo中查看完整的示例代碼https://github.com/easy-swool...

Easyswoole項(xiàng)目主頁(yè):http://easyswoole.com/
Easyswoole github 主倉(cāng)庫(kù)https://github.com/easy-swool... ,如果你覺(jué)得我們的努力有對(duì)你起到幫助作用,記得給個(gè)star

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/31668.html

相關(guān)文章

  • php極簡(jiǎn)框架 one 1.6.7發(fā)布,新增分布式并發(fā)模型Actor

    摘要:新增新增模型方法,主動(dòng)刷新數(shù)據(jù)表結(jié)構(gòu)緩存。分布式并發(fā)模型是什么是一種與共享內(nèi)存對(duì)應(yīng)的并發(fā)模型,具有資源獨(dú)占性。都分布在不同的機(jī)器上。 One - 極簡(jiǎn) . 高性能 . 松耦合 . 分布式 . 可運(yùn)行于多種環(huán)境(cli,apache/php-fpm,swoole) 碼云: https://gitee.com/vicself/onegithub: https://github.com/li...

    劉明 評(píng)論0 收藏0
  • 聯(lián)網(wǎng)并發(fā)編程網(wǎng)絡(luò)編程中的線程模型

    摘要:如需了解更多物聯(lián)網(wǎng)網(wǎng)絡(luò)編程知識(shí)請(qǐng)點(diǎn)擊物聯(lián)網(wǎng)云端開發(fā)武器庫(kù)物聯(lián)網(wǎng)高并發(fā)編程之網(wǎng)絡(luò)編程中的線程模型值得說(shuō)明的是,具體選擇線程還是進(jìn)程,更多是與平臺(tái)及編程語(yǔ)言相關(guān)。 如需了解更多物聯(lián)網(wǎng)網(wǎng)絡(luò)編程知識(shí)請(qǐng)點(diǎn)擊:物聯(lián)網(wǎng)云端開發(fā)武器庫(kù) 物聯(lián)網(wǎng)高并發(fā)編程之網(wǎng)絡(luò)編程中的線程模型 值得說(shuō)明的是,具體選擇線程還是進(jìn)程,更多是與平臺(tái)及編程語(yǔ)言相關(guān)。例如 C 語(yǔ)言使用線程和進(jìn)程都可以(例如 Nginx 使用進(jìn)程...

    ziwenxie 評(píng)論0 收藏0
  • PHP下用Swoole實(shí)現(xiàn)Actor并發(fā)模型

    摘要:協(xié)程與信箱得益于,我們可以基于的協(xié)程與快速實(shí)現(xiàn)一個(gè)信箱模式調(diào)度。樣例代碼比如在一個(gè)聊天室中,我們可以定義一個(gè)房間模型。 什么是Actor? Actor對(duì)于PHPer來(lái)說(shuō),可能會(huì)比較陌生,寫過(guò)Java的同學(xué)會(huì)比較熟悉,Java一直都有線程的概念(雖然PHP有Pthread,但不普及),它是一種非共享內(nèi)存的并發(fā)模型,每個(gè)Actor內(nèi)的數(shù)據(jù)獨(dú)立存在,Actor之間通過(guò)消息傳遞的形式進(jìn)行交互調(diào)...

    GeekQiaQia 評(píng)論0 收藏0
  • Akka系列(六):Actor解決了什么問(wèn)題?

    摘要:原文鏈接解決了什么問(wèn)題使用模型來(lái)克服傳統(tǒng)面向?qū)ο缶幊棠P偷木窒扌?,并?yīng)對(duì)高并發(fā)分布式系統(tǒng)所帶來(lái)的挑戰(zhàn)。在某些情況,這個(gè)問(wèn)題可能會(huì)變得更糟糕,工作線程發(fā)生了錯(cuò)誤但是其自身卻無(wú)法恢復(fù)。 這段時(shí)間由于忙畢業(yè)前前后后的事情,拖更了很久,表示非常抱歉,回歸后的第一篇文章主要是看到了Akka最新文檔中寫的What problems does the actor model solve?,閱讀完后覺(jué)...

    Carson 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<