Swoole進階——01 進程(管道通信)


定義

進程就是正在運行的程序的一個實例。

例如,我們在某個終端去執行一個php腳本,這個時候就可以認爲是開啓了一個進程。



基本使用


1. 創建一個子進程對象

// 普通形式
$process = new swoole_process('callback_function', true);

// oop形式
swoole_process::__construct(callable $function, $redirect_stdin_stdout = false, $create_pipe = true);

// 啓用命名空間
Swoole\Process::__construct(callable $function, $redirect_stdin_stdout = false, $create_pipe = true)

參數說明

  • $function,子進程創建成功後要執行的函數,底層會自動將函數保存到對象的callback屬性上。如果希望更改執行的函數,可賦值新的函數到對象的callback屬性。

  • $redirect_stdin_stdout,重定向子進程的標準輸入和輸出。啓用此選項後,在子進程內輸出內容將不是打印屏幕,而是寫入到主進程管道。讀取鍵盤輸入將變爲從管道中讀取數據。默認爲阻塞讀取。

  • $pipe_type,管道類型,啓用$redirect_stdin_stdout後,此選項將忽略用戶參數,強制爲1。如果子進程內沒有進程間通信,可以設置爲 0


管道類型

0:不創建管道

1:創建SOCK_STREAM類型管道

2:創建SOCK_DGRAM類型管道

啓用$redirect_stdin_stdout 後,此選項將忽略用戶參數,強制爲1。

管道類型爲DGRAM數據報時,read可以讀取完整的一個數據包。

管道類型爲STREAM時,read是流式的,需要自行處理包完整性問題。

對於數據完整性要求較高時,強烈建議不開啓 $redirect_stdin_stdout。



2. 啓動子進程

function swoole_process->start()

創建成功返回子進程的PID,創建失敗返回false。

可使用swoole_errno和swoole_strerror得到錯誤碼和錯誤信息。

  • $process->pid 屬性爲子進程的PID

  • $process->pipe 屬性爲管道的文件描述符

執行後子進程會保持父進程的內存和資源,如父進程內創建了一個redis連接,那麼在子進程會保留此對象,所有操作都是對同一個連接進行的。



3. 往管道寫入數據

function Process->write(string $data);
  • 在子進程內調用write,父進程可以調用read接收此數據

  • 在父進程內調用write,子進程可以調用read接收此數據



4. 從管道中讀取數據

function Process->read(int $buffer_size=8192)

讀取成功返回二進制數據字符串,讀取失敗返回false。



5. 執行外部程序

function Process->exec(string $execfile, array $args)
  • $execfile指定可執行文件的絕對路徑,如 “/usr/bin/python”

  • $args是一個數組,是exec的參數列表,如 array(‘test.py’, 123),相當與python test.py 123


特別注意

$execfile必須使用絕對路徑,否則會報文件不存在錯誤。

由於exec系統調用會使用指定的程序覆蓋當前程序,子進程需要讀寫標準輸出與父進程進行通信。

如果未指定redirect_stdin_stdout = true,執行exec後子進程與父進程無法通信。



簡單例子

// 1.創建子進程對象
$process = new swoole_process(function(swoole_process $pro){
    
    // 3.調用外部程序
    $pro->exec("/usr/local/php/bin/php",[__DIR__.'../server/http.php']);

}, true);


// 2.啓動子進程
$pid = $process->start();

echo "子進程id:".$pid.PHP_EOL;


// 4.回收子進程
swoole_process::wait();






使用場景


需求

有10個url地址,需要獲取這10個地址裏面的內容,寫入文件或數據庫。

PHP原始方案

同步執行這10個url,順序獲取一個個url裏的內容。

問題:執行慢

Swoole process方案

引入swoole process,按需開啓多個子進程執行。



例子

<?php

// 進程講解例子

// 開始標誌
echo "process-start-time".date("Ymd H:i:s").PHP_EOL;


// 1.定義子進程對象數組
$workers = [];


// 2.定義url數組
$urls = [
    'http:www.baidu.com',
    'http:www.qq.com',
    'http:www.sina.com',
    'http:www.jd.com',
    'http:www.imooc.com',
    'http:www.taobao.com',
];


// 3.PHP原生做法
// foreach($urls as $url){
//     $content[] = file_get_contents($url);
// }


// 3.swoole process做法
for($i = 0; $i < 6; $i++){

    // 4.創建子進程對象
    $process = new swoole_process(function(swoole_process $worker) use($i, $urls) {
        
        // 5.調用自定義方法
        $content = curlData($urls[$i]);
        //echo $content.PHP_EOL;

        // 6.往管道里寫入內容
        $worker->write($content.PHP_EOL);

    },true);


    // 7.啓動子進程
    $pid = $process->start();


    // 8.把子進程對象加到workers數組
    $workers[$pid] = $process;
}


// 9.打印workers
foreach ($workers as $process) {
    echo $process->read();
}


// 結束標誌
echo "process-end-time".date("Ymd H:i:s");


// 自定義方法(模擬場景,非真實代碼)
function curlData($url){
    sleep(1);
    return $url."success".PHP_EOL;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章