用 PHP V5 開發多任務應用程式_PHP教程

來源:互聯網
上載者:User
許多 PHP 開發人員認為,由於標準的 PHP 缺少線程功能,因此實際 PHP 應用程式不可能執行多任務處理。例如,如果應用程式需要其他 Web 網站的資訊,那麼在遠程檢索完成之前它都必須停止。這是錯誤的!通過本文瞭解如何使用 stream_select 和 stream_socket_client 實現進程內 PHP 多任務處理。

  PHP 不支援線程。儘管如此,與前述大多數 PHP 開發人員所相信的想法形成對比的是,PHP 應用程式可以 執行多任務處理。讓我們開始儘可能清晰地描述一下 “多任務” 和 “線程” 對於 PHP 編程的意義。

  並發的種類

  首先拋開幾個和主題無關的例子。PHP 與多任務或並發的關係十分複雜。在較高層次上,PHP 經常涉及多任務:以多任務方式使用 標準的伺服器端 PHP 安裝 —— 例如,作為 Apache 模組。換句話說,若干個客戶機 —— 網頁瀏覽器 —— 可以同時請求同一個 PHP 解釋的頁面,而 Web 服務器將差不多同時返回所有這些頁面。

  一個 Web 頁面不會妨礙其他 Web 頁面的發送,儘管可能會由於諸如伺服器記憶體或網路頻寬之類的受限資源而使它們相互之間略有妨礙。這樣,實現並發 的系統級需求可能適合使用基於 PHP 的解決方案。就實現而言,PHP 允許它的管理 Web 服務器負責實現並發。

  Ajax 名下的用戶端並發近幾年來也已成為開發人員關注的焦點。雖然 Ajax 的含義已經變得十分模糊,但是它的一個方面是瀏覽器顯示可以同時執行計算和 保留對諸如選擇功能表項目之類的使用者操作的響應。這實際上就是某種 多任務。用 PHP 編碼的 Ajax 就是這樣 —— 但是不涉及任何特定的 PHP;用於其他語言的 Ajax 架構均以完全相同的方法操作。

  只粗略地涉及 PHP 的第三個並發執行個體是 PHP/TK。PHP/TK 是 PHP 的擴充,用於為核心 PHP 提供可移植圖形化使用者介面(GUI)綁定。PHP/TK 允許用 PHP 編寫代碼構造案頭 GUI 應用程式。其基於事件的特性將類比一種易於掌握並且比線程更少出錯的並發形式。此外,並發是 “繼承” 自一項輔助技術,而不是 PHP 的準系統。

  向 PHP 本身添加線程支援的實驗已經做過多次。據我所知,沒有一次是成功的。但是,Ajax 架構和 PHP/TK 的面向事件的實現表明事件可能比線程能更好地體現 PHP 的並發。PHP V5 證明事實確實如此。

  PHP V5 將提供 stream_select()

  使用標準的 PHP V4 和更低版本,必須按順序執行 PHP 應用程式的所有工作。例如,如果程式需要在兩個商業網站檢索商品的價格,則請求第一個網站的價格,等待至響應到達,再請求第二個網站的價格,然後再次等待。

  如果程式請求同時完成若干項任務會怎麼樣?總體來看,程式將在一段時間內完成,在這段時間內,將始終進行連續處理。

  第一個樣本

  新的 stream_select 函數及它的幾個助手使這成為可能。請考慮以下樣本。

  清單 1. 同時請求多個 HTTP 頁面

<?php
echo "Program starts at ". date(h:i:s) . ".";
$timeout=10;
$result=array();
$sockets=array();
$convenient_read_block=8192;
/* Issue all requests simultaneously; theres no blocking. */
$delay=15;
$id=0;
while ($delay > 0) {
 $s=stream_socket_client("phaseit.net:80", $errno,
  $errstr, $timeout,
  STREAM_CLIENT_ASYNC_CONNECT|STREAM_CLIENT_CONNECT);
 if ($s) {
  $sockets[$id++]=$s;
  $http_message="GET /demonstration/delay?delay=" .
   $delay . " HTTP/1.0Host: phaseit.net";
  fwrite($s, $http_message);
 } else {
  echo "Stream " . $id . " failed to open correctly.";
 }
 $delay -= 3;
}
while (count($sockets)) {
 $read=$sockets;
 stream_select($read, $w=null, $e=null, $timeout);
 if (count($read)) {
  /* stream_select generally shuffles $read, so we need to
  compute from which socket(s) were reading. */
  foreach ($read as $r) {
   $id=array_search($r, $sockets);
   $data=fread($r, $convenient_read_block);
   /* A socket is readable either because it has
   data to read, OR because its at EOF. */
   if (strlen($data) == 0) {
    echo "Stream " . $id . " closes at " . date(h:i:s) . ".";
    fclose($r);
    unset($sockets[$id]);
   } else {
    $result[$id] .= $data;
   }
  }
 } else {
  /* A time-out means that *all* streams have failed
  to receive a response. */
  echo "Time-out!";
  break;
 }
}
?>

  如果運行此清單,您將看到如下所示的輸出。

  清單 2. 從清單 1 中的程式獲得的典型輸出

Program starts at 02:38:50.
Stream 4 closes at 02:38:53.
Stream 3 closes at 02:38:56.
Stream 2 closes at 02:38:59.
Stream 1 closes at 02:39:02.
Stream 0 closes at 02:39:05.

  瞭解這其中的工作原理至關重要。在較高層次上,第一個程式將發出幾個 HTTP 要求並接收 Web 服務器發送給它的頁面。雖然生產應用程式將很可能尋找若干個 Web 服務器的地址 —— 可能是 google.com、yahoo.com、ask.com 等 —— 但是此樣本將把它的所有請求發送到位於 Phaseit.net 的企業伺服器上,只為降低複雜度。

  Web 頁面請求在延遲(可變)後返回結果,如下所示。如果程式按順序發出請求,則需花費大約 15+12+9+6+3 (45) 秒鐘才能完成。如清單 2 所示,它實際上花費 15 秒鐘完成。效能提高了三倍。

  使這成為可能的是 PHP V5 的新 stream_select 函數。請求都是以常規方法發起,方法為開啟幾個 stream_socket_client 並向對應於 http://phaseit.net/demonstration/delay?delay=$DELAY 的每個 stream_socket_client 寫入 GET。如果您通過瀏覽器請求此 URL,則在幾秒鐘之後,您將看到:

Starting at Thu Apr 12 15:05:01 UTC 2007.
Stopping at Thu Apr 12 15:05:05 UTC 2007.
4 second delay.

  延遲伺服器將作為 CGI 實現,如下所示:

  清單 3. 延遲伺服器實現

#!/bin/sh
echo "Content-type: text/html
<HTML> <HEAD></HEAD> <BODY>"
echo "Starting at `date`."
RR=`echo $REQUEST_URI | sed -e s/.*?//`
DELAY=`echo $RR | sed -e s/delay=//`
sleep $DELAY
echo "<br>Stopping at `date`."
echo "<br>$DELAY second delay.</body></html>"

  雖然清單 3 的特殊實現特定於 UNIX?,但是本文中幾乎所有實現都將很好地應用於 Windows?(尤其是 Windows 98 以後的版本)或 PHP 的 UNIX 安裝。特別地,清單 1 可以託管在任意一個作業系統中。因此,Linux? 和 Mac OS X 都是 UNIX 變體,因此這裡所有的代碼都可以在兩者的任意一種中運行。

  按照以下順序向延遲伺服器發出請求。

  清單 4. 進程啟動順序

delay=15
delay=12
delay= 9
delay= 6
delay= 3

  stream_select 的作用是儘可能快速地接收結果。在這種情況下,它執行的順序與發出結果的順序剛好相反。3 秒後,第一個頁面已經準備好讀取。程式的這一部分也符合常規 PHP —— 在本例中,使用 fread。就像在其他 PHP 程式一樣,讀取可以很好地通過 fgets 完成。

  處理將以同樣的方法繼續。程式將在 stream_select 停止,直至資料就緒。重要的一點是,只要任何 串連具有資料,不管順序怎樣,程式都將開始讀取。這是程式進行多任務處理或並發處理來自多個請求的結果的方法。

  注意,這沒有對主機 CPU 造成任何負擔。經常會遇到這樣一些連網程式,以 CPU 使用率急速上升至 100% 的方式在 while 中使用 fread。那種情況不會出現在這裡,因為 stream_select 擁有支援立即響應所需的屬性(只要有任何讀取資訊),但是它將在各讀取操作間隙的等待時間內產生可忽略的 CPU 負載。

  必備的 stream_select() 知識

  諸如此類的基於事件的編程並不是最基本的。雖然清單 1 被簡化到只包含最基本要素,但是涉及作為多任務應用程式必要元素的回調或協調的任何編碼,比簡單的程式順序更讓人覺得陌生。在這種情況下,大多數挑戰集中在 $read 數組上。注意,它是一個引用;stream_select 將通過改變 $read 的內容返回重要訊息。就像指標是 C 的最大絆腳石一樣,引用似乎是 PHP 中最讓程式員感到棘手的一部分。

  您可以使用這項技術向任意個外部 Web 網站發出請求,確信您的程式會儘快收到所有結果,而無需等待其他請求。實際上,該技術將正確處理所有 TCP/IP 串連,而不只是 Web 連接埠 80 上的串連,因此您可以大體上管理 LDAP 檢索、SMTP 傳輸、SOAP 請求等。

  但那不是全部。PHP V5 將管理 “流” 之類的各種串連,而不僅是簡單的通訊端。PHP 的 Client URL library (CURL) 支援 HTTPS 認證、FTP 上傳、cookie 等。(CURL 允許 PHP 應用程式使用各種協議串連至伺服器)。由於 CURL 將提供流介面,因此從程式的角度來看,串連是透明的。下一個部分將展示 stream_select 如何多路傳輸本地計算。

  對於 stream_select 還有幾點需要注意。它還在進行文檔整理,因為即使最新的 PHP 書籍都沒有涉列它。可在 Web 上獲得的

http://www.bkjia.com/PHPjc/509212.htmlwww.bkjia.comtruehttp://www.bkjia.com/PHPjc/509212.htmlTechArticle許多 PHP 開發人員認為,由於標準的 PHP 缺少線程功能,因此實際 PHP 應用程式不可能執行多任務處理。例如,如果應用程式需要其他 Web 站...

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.