国产+高潮+在线,国产 av 仑乱内谢,www国产亚洲精品久久,51国产偷自视频区视频,成人午夜精品网站在线观看

如何使用workerman實(shí)現(xiàn)多進(jìn)程主動(dòng)輪詢外部服務(wù)器?

typing
   首先感謝walkor大大創(chuàng)造了一個(gè)如此優(yōu)秀的php框架. 其中的多進(jìn)程優(yōu)勢(shì)、異步IO、定時(shí)器和libevent事件輪詢庫、支持高并發(fā)等特性,讓我眼前為之一亮.

   我看了手冊(cè)和demo,在做服務(wù)器方面已經(jīng)提供了很好地實(shí)例和說明,可我目前遇到一個(gè)需求:將php服務(wù)器模擬客戶端對(duì)外部服務(wù)器進(jìn)行主動(dòng)輪詢.

如示意圖:
[attach]67[/attach]

1.創(chuàng)建一個(gè)主進(jìn)程(守護(hù)進(jìn)程),一旦啟動(dòng)長(zhǎng)時(shí)間運(yùn)行在后臺(tái),即使關(guān)掉瀏覽器頁面.

主線程定時(shí)查詢數(shù)據(jù)庫(MySQL),一旦發(fā)現(xiàn)有符合條件的URL(可能多條),即創(chuàng)建對(duì)應(yīng)的數(shù)量的子進(jìn)程.
子進(jìn)程也需要長(zhǎng)時(shí)間存在,定時(shí)輪詢URL對(duì)應(yīng)的服務(wù)器取回?cái)?shù)據(jù).
子進(jìn)程一旦取回所需要的數(shù)據(jù),將結(jié)果保存到數(shù)據(jù)庫,自我結(jié)束(或被主進(jìn)程關(guān)閉).

目前的想法是在worker類里增加一個(gè)輪詢方法,但是感覺這樣破壞了框架結(jié)構(gòu).
難點(diǎn):
1.如何創(chuàng)建子線程?

如何實(shí)現(xiàn)定時(shí)輪詢?
3.子線程如何自我關(guān)閉?

ps:
樓主從事iOS客戶端開發(fā),剛接觸PHP幾天,正在努力學(xué)習(xí)中,無奈項(xiàng)目期限太緊,苦思無果,前來寶地求助,希望能幫忙提供思路或給出簡(jiǎn)單demo.

再次感謝walkor大大和熱心的朋友們.

8659 5 0
5個(gè)回答

walkor 打賞

首先贊一個(gè),提問的非常有條理。

說說我的看法,
1、不能每個(gè)url一個(gè)進(jìn)程,如果url數(shù)量控制不好,會(huì)造成創(chuàng)建太多進(jìn)程導(dǎo)致服務(wù)器內(nèi)存資源耗盡
2、子進(jìn)程不必自我結(jié)束,進(jìn)程能復(fù)用就盡量復(fù)用
3、業(yè)務(wù)比較簡(jiǎn)單,可以只開一個(gè)進(jìn)程,并使用IO復(fù)用(workerman的異步IO或者curl_multi等),性能比多進(jìn)程多線程更高

下面是一個(gè)定時(shí)器例子,只使用一個(gè)worker進(jìn)程,定時(shí)查詢數(shù)據(jù)庫獲得url,并異步批量請(qǐng)求這些url。

文件名 :Applications/HttpPoll/start.php

<?php
use Workerman\Worker;
use Workerman\Lib\Timer;
use Workerman\Connection\AsyncTcpConnection;

$worker = new Worker();

$worker->onWorkerStart = function(){
    Timer::add(5, 'http_poll');
};

function http_poll()
{
    $url_array = get_url_array_from_db();
    // 這里使用的是workerman的異步IO AsyncTcpConnection。也可以使用curl,那樣對(duì)http支持更好一些
    foreach($url_array as $url)
    {
         // 建立異步鏈接
         $connection = new AsyncTcpConnection('tcp://'.$url.':80');
         // $connection 是個(gè)對(duì)象,可以把一些數(shù)據(jù)以屬性的形式存儲(chǔ)進(jìn)去,使用的時(shí)候再讀取。這里把url存起來
         $connection->url = $url;
         // 鏈接失敗時(shí)的處理
         $connection->onError = function($connection, $err_no, $err_msg)
         {
            echo "\n!!!!!!!!!!!!{$connection->url}!!!!!!!!!!!!!!!\n","fail $err_no $err_msg";
         };
         // 一旦鏈接上服務(wù)端,則發(fā)起http請(qǐng)求
         $connection->onConnect = function($connection)
         {
            $connection->send("GET / HTTP/1.1\r\nConnection: close\r\nHost: {$connection->url}\r\nAccept: text/html\r\nUser-Agent: Mozilla/5.0\r\n\r\n");
         };
         // 一旦收到數(shù)據(jù)打印。注意這里AsyncTcpConnection指定的是tcp,沒有處理協(xié)議,這里接收的數(shù)據(jù)是分段的http協(xié)議數(shù)據(jù)
         $connection->onMessage = function($connection, $http_buffer)
         {
            echo "\n----------$connection->url---------\n{$http_buffer}\n";
            $connection->close();
         };
    }
}

// 從數(shù)據(jù)庫中讀取url
function get_url_array_from_db()
{
    return array('www.baidu.com', 'www.163.com', 'www.sina.com');
}

注意上面 http_poll 函數(shù)中使用的是workerman自帶的異步IO,AsycTcpConnection,由于我沒有實(shí)現(xiàn)客戶端的http協(xié)議(實(shí)現(xiàn)方法參見手冊(cè)協(xié)議訂制部分),這里僅使用了tcp,沒有分包,可能會(huì)導(dǎo)致onMessage中的$http_buffer是分段發(fā)來的。

http_poll中可用curl_multi_*函數(shù)替換workerman的異步IO,也可以批量獲取url,并且對(duì)http協(xié)議支持的更好。使用方法及例子見: http://php.net/manual/en/function.curl-multi-exec.php

  • 暫無評(píng)論
typing

感謝walkor大大的耐心回復(fù).

可是實(shí)際的需求比示意圖要復(fù)雜:
1.從數(shù)據(jù)庫中取出的不是一個(gè)簡(jiǎn)單地URL,而是一個(gè)taskId,要根據(jù)taskId去讀取另一張表,要依次定時(shí)輪詢表中的URL.

Task A 中的URL_A_1 與 Task B中的URL_B_1 可能需要同時(shí)發(fā)起(比如在晚上9點(diǎn)整同時(shí)請(qǐng)求n臺(tái)服務(wù)器的數(shù)據(jù)).
該工程會(huì)在多臺(tái)服務(wù)器上分布式部署,實(shí)現(xiàn)集群效果.

所以如果"可以只開一個(gè)進(jìn)程,并使用IO復(fù)用"的話,雖然也可以實(shí)現(xiàn),但是我擔(dān)心在讀寫數(shù)據(jù)庫時(shí)候會(huì)有阻塞,導(dǎo)致任務(wù)是依次執(zhí)行的,而達(dá)不到并發(fā)的要求.另外復(fù)用一個(gè)進(jìn)程,也可能會(huì)增加任務(wù)調(diào)度的邏輯復(fù)雜度.

如果我控制好worker進(jìn)程的數(shù)量,解決服務(wù)器內(nèi)存資源耗盡的問題后(如果2G內(nèi)存,每個(gè)worker進(jìn)程占用5m,那么我控制最多創(chuàng)建 400個(gè)進(jìn)程),是否還有其它的隱患?

我在您的demo基礎(chǔ)上改了一下,您看寫得對(duì)不對(duì)?

<?php
use Workerman\Worker;
use Workerman\Lib\Timer;
use Workerman\Connection\AsyncTcpConnection;

$main_worker = new Worker();

$main_worker->onWorkerStart = function(){
    Timer::add(5, 'sub_worker_create_poll');
};

$sub_worker_array = array();

function sub_worker_create_poll(){
    $task_array = get_taskId_array_from_db();
    foreach($task_array as $task_id)
    {
        if(empty($sub_worker_array)){
            $sub_worker = new Worker();
            $sub_worker->onWorkerStart = function(){
                Timer::add(1, 'http_poll');
            };

            $sub_worker_array = $sub_worker;
        }else{
            echo "任務(wù)".$task_id."已創(chuàng)建進(jìn)程";
        }
    }
}

function http_poll()
{
    $task_id = ? //如何知道當(dāng)前的函數(shù)是被哪個(gè)worker調(diào)用的? 然后取到$sub_worker_array對(duì)應(yīng)的task_id?
    $url_array = get_url_array_from_db_by_taskId($task_id);
// 這里使用的是workerman的異步IO AsyncTcpConnection。也可以使用curl,那樣對(duì)http支持更好一些
    foreach($url_array as $url)
    {
        // 建立異步鏈接
        $connection = new AsyncTcpConnection('tcp://'.$url.':80');
        // $connection 是個(gè)對(duì)象,可以把一些數(shù)據(jù)以屬性的形式存儲(chǔ)進(jìn)去,使用的時(shí)候再讀取。這里把url存起來
        $connection->url = $url;
        // 鏈接失敗時(shí)的處理
        $connection->onError = function($connection, $err_no, $err_msg)
        {
            echo "\n!!!!!!!!!!!!{$connection->url}!!!!!!!!!!!!!!!\n","fail $err_no $err_msg";
        };
        // 一旦鏈接上服務(wù)端,則發(fā)起http請(qǐng)求
        $connection->onConnect = function($connection)
        {
            $connection->send("GET / HTTP/1.1\r\nConnection: close\r\nHost: {$connection->url}\r\nAccept: text/html\r\nUser-Agent: Mozilla/5.0\r\n\r\n");
        };
        // 一旦收到數(shù)據(jù)打印。注意這里AsyncTcpConnection指定的是tcp,沒有處理協(xié)議,這里接收的數(shù)據(jù)是分段的http協(xié)議數(shù)據(jù)
        $connection->onMessage = function($connection, $http_buffer)
        {
            echo "\n----------$connection->url---------\n{$http_buffer}\n";
            $connection->close();
        };
    }
}

// 從數(shù)據(jù)庫中讀取task_id
function get_taskId_array_from_db()
{
    return array('task_id_1', 'task_id_2', 'task_id_3');
}

// 根據(jù)task_id從數(shù)據(jù)庫中讀取對(duì)應(yīng)的URLs
function get_url_array_from_db_by_taskId($task_id)
{
    return array('www.baidu.com?param='.$task_id, 'www.163.com?param='.$task_id, 'www.sina.com?param='.$task_id);
}
  • 暫無評(píng)論
walkor 打賞

@Typing
不能在子進(jìn)程中再創(chuàng)建子進(jìn)程,進(jìn)程越來越多會(huì)導(dǎo)致不可控

一個(gè)簡(jiǎn)單的方法是創(chuàng)建多個(gè)worker進(jìn)程,每個(gè)進(jìn)程定時(shí)從數(shù)據(jù)庫中領(lǐng)取一個(gè)taskid去執(zhí)行,有點(diǎn)想消息隊(duì)列。這樣也可以方便分布式部署。代碼也最簡(jiǎn)單

  • 暫無評(píng)論
typing

@walkor
但是數(shù)據(jù)庫的taskid數(shù)量是不確定的,會(huì)動(dòng)態(tài)變化,不知道該創(chuàng)建多少個(gè)?
是不是還得有個(gè)進(jìn)程來管理這些子進(jìn)程?

  • 暫無評(píng)論
walkor 打賞

使用workerman,new 一個(gè)Worker,設(shè)置成固定的進(jìn)程數(shù)(count屬性),然后去輪詢數(shù)據(jù)庫即可。
進(jìn)程管理根本不用擔(dān)心,workerman會(huì)自己管理

taskid數(shù)量變化也沒啥問題,比如有1000個(gè)taskid,100個(gè)進(jìn)程輪詢處理,簡(jiǎn)單的任務(wù)可能1秒就全部做完了

  • 暫無評(píng)論
年代過于久遠(yuǎn),無法發(fā)表回答
??