仿照async/await風格對Swoole4協程的簡單包裝

Swoole官方文檔中對協程的示例大多按照一次請求一個協程(或腳本併發大量協程)的方式來舉例說明,這種使用方式下提高的是總體的性能,而非單次請求的響應時間.
要提高單次請求的響應效率(或提高非網絡服務下php腳本代碼的運行效率),須要在業務代碼中主動使用協程來處理那些可併發的,耗時的代碼.
這時便涉及到協程數據交互的狀況,官方文檔中使用chan舉了一個生產者消費者的例子,可是若是業務代碼都按照這個風格的話較爲複雜.
js及c#的async/await風格使用相對簡單,因此結合Swoole協程的csp模型及php語法狀況,仿照async/await的風格作了以下簡單包裝.

包裝方法代碼

class CoTask {

    protected $chan = null;

    public function __construct(\Chan $chan){ 
        $this->chan = $chan;        
    }

    public function wait(){ 
        if($this->chan instanceof \Chan){
            $result = $this->chan->pop();
            $this->chan = null;
            if(!empty($result['exception']) && $result['exception'] instanceof \Throwable){
                throw $result['exception'];
            }else{
                return $result['result'];
            }
        }else{
            throw new \Exception('exception');
        }
    }
}

function co_run($func){
    $chan = new \Chan(1);
    $task = new \CoTask($chan);
    go(function() use ($chan,$func){
        $result = ['result' => null,'exception' => null];
        try{
            $result['result'] = $func();
        }catch (\Throwable $e){
            $result['exception'] = $e;
        }
        $chan->push($result);
    });
    return $task;
}

function co_wait(&$task){
    if($task instanceof \CoTask){
        $task = $task->wait();
    }
    return $task;
}

調用舉例

$test = co_run(function(){
    //執行代碼並返回結果
});
//執行其餘代碼
co_wait($test);//因爲使用了chan的pop方法,因此須要當前在協程上下文
var_dump($test);

PHP7.4後箭頭函數調用舉例

$test = co_run(fn() => "單行的執行代碼,如多行仍需按照原有方式");
//執行其餘代碼
co_wait($test);//因爲使用了chan的pop方法,因此須要當前在協程上下文
var_dump($test);

總結

通過這樣簡單的包裝,能夠在業務代碼中存在可併發的屢次調用或循環調用場景下使用,壓縮單次處理時間.
相關文章
相關標籤/搜索