定義
進程就是正在運行的程序的一個實例。
例如,我們在某個終端去執行一個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;
}