日韩欧美国产精品免费一二-日韩欧美国产精品亚洲二区-日韩欧美国产精品专区-日韩欧美国产另-日韩欧美国产免费看-日韩欧美国产免费看清风阁

LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

用 PHP V5 開發(fā)多任務應用程序

admin
2012年3月16日 10:20 本文熱度 3021
  許多 php 開發(fā)人員認為,由于標準的 PHP 缺少線程功能,因此實際 PHP 應用程序不可能執(zhí)行多任務處理。例如,如果應用程序需要其他 Web 站點的信息,那么在遠程檢索完成之前它都必須停止。這是錯誤的!通過本文了解如何使用 stream_select 和 stream_socket_client 實現(xiàn)進程內(nèi) PHP 多任務處理。

  PHP 不支持線程。盡管如此,與前述大多數(shù) PHP 開發(fā)人員所相信的想法形成對比的是,PHP 應用程序可以 執(zhí)行多任務處理。讓我們開始盡可能清晰地描述一下 “多任務” 和 “線程” 對于 PHP 編程的意義。

  并發(fā)的種類

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

  一個 Web 頁面不會妨礙其他 Web 頁面的發(fā)送,盡管可能會由于諸如服務器內(nèi)存或網(wǎng)絡帶寬之類的受限資源而使它們相互之間略有妨礙。這樣,實現(xiàn)并發(fā) 的系統(tǒng)級需求可能適合使用基于 PHP 的解決方案。就實現(xiàn)而言,PHP 允許它的管理 Web 服務器負責實現(xiàn)并發(fā)。

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

  只粗略地涉及 PHP 的第三個并發(fā)實例是 PHP/TK。PHP/TK 是 PHP 的擴展,用于為核心 PHP 提供可移植圖形用戶界面(GUI)綁定。PHP/TK 允許用 PHP 編寫代碼構造桌面 GUI 應用程序。其基于事件的特性將模擬一種易于掌握并且比線程更少出錯的并發(fā)形式。此外,并發(fā)是 “繼承” 自一項輔助技術,而不是 PHP 的基本功能。

  向 PHP 本身添加線程支持的試驗已經(jīng)做過多次。據(jù)我所知,沒有一次是成功的。但是,Ajax 框架和 PHP/TK 的面向事件的實現(xiàn)表明事件可能比線程能更好地體現(xiàn) PHP 的并發(fā)。PHP V5 證明事實確實如此。

  PHP V5 將提供 stream_select()

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

  如果程序請求同時完成若干項任務會怎么樣?總體來看,程序將在一段時間內(nèi)完成,在這段時間內(nèi),將始終進行連續(xù)處理。

  第一個示例

  新的 stream_select 函數(shù)及它的幾個助手使這成為可能。請考慮以下示例。

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

<?php
echo "PRogram starts at ". date('h:i:s') . ".\n";

$timeout=10;
$result=array();
$sockets=array();
$convenient_read_block=8192;

/* Issue all requests simultaneously; there's 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.0\r\nHost: phaseit.net\r\n\r\n";
  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) we're 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 it's at EOF. */
   if (strlen($data) == 0) {
    echo "Stream " . $id . " closes at " . date('h:i:s') . ".\n";
    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!\n";
  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.

  了解這其中的工作原理至關重要。在較高層次上,第一個程序將發(fā)出幾個 HTTP 請求并接收 Web 服務器發(fā)送給它的頁面。雖然生產(chǎn)應用程序將很可能尋找若干個 Web 服務器的地址 —— 可能是 google.com、yahoo.com、ask.com 等 —— 但是此示例將把它的所有請求發(fā)送到位于 Phaseit.net 的企業(yè)服務器上,只為降低復雜度。

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

  使這成為可能的是 PHP V5 的新 stream_select 函數(shù)。請求都是以常規(guī)方法發(fā)起,方法為打開幾個 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 實現(xiàn),如下所示:

  清單 3. 延遲服務器實現(xiàn)

#!/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 的特殊實現(xiàn)特定于 UNIX?,但是本文中幾乎所有實現(xiàn)都將很好地應用于 Windows?(尤其是 Windows 98 以后的版本)或 PHP 的 UNIX 安裝。特別地,清單 1 可以托管在任意一個操作系統(tǒng)中。因此,linux? 和 Mac OS X 都是 UNIX 變體,因此這里所有的代碼都可以在兩者的任意一種中運行。

  按照以下順序向延遲服務器發(fā)出請求。

  清單 4. 進程啟動順序

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

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

  處理將以同樣的方法繼續(xù)。程序將在 stream_select 停止,直至數(shù)據(jù)就緒。重要的一點是,只要任何 連接具有數(shù)據(jù),不管順序怎樣,程序都將開始讀取。這是程序進行多任務處理或并發(fā)處理來自多個請求的結果的方法。

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

  必備的 stream_select() 知識

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

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

  但那不是全部。PHP V5 將管理 “流” 之類的各種連接,而不僅是簡單的套接字。PHP 的 Client URL library (CURL) 支持 HTTPS 證書、FTP 上傳、cookie 等。(CURL 允許 PHP 應用程序使用各種協(xié)議連接至服務器)。由于 CURL 將提供流接口,因此從程序的角度來看,連接是透明的。下一個部分將展示 stream_select 如何多路傳輸本地計算。

  對于 stream_select 還有幾點需要注意。它還在進行文檔整理,因為即使最新的 PHP 書籍都沒有涉列它。可在 Web 上獲得的幾個代碼示例完全不能工作或者讓人產(chǎn)生混淆。stream_select 的第二個和第三個參數(shù)用于管理與清單 1 的 read 通道相對應的 write 和 exception 通道,應當始終為 null。除了少數(shù)例外情況,在可寫通道或異常通道中選擇這兩個參數(shù)是錯誤的。除非您有經(jīng)驗,否則請堅持可讀選擇。

  此外,至少在 PHP V5.1.2 之前,stream_select 還明顯存在錯誤。最重要的是,不能信任函數(shù)的返回值。雖然我尚未調試過實現(xiàn),但是經(jīng)驗告訴我,可以安全地測試清單 1 中的 count($read),但是測試 stream_select 本身的返回值并不 安全(盡管有官方文檔)。

  本地 PHP 并發(fā)

  示例及上面的大部分討論主要討論了如何同時管理若干個遠程資源并接收到達的結果,而不是按照最初請求的順序等待處理各個請求。這肯定是 PHP 并發(fā)的重要應用。實際應用程序的速度有時候可以提高 10 倍或更多。

  如果出現(xiàn)性能衰退怎么辦?有沒有一種方法可以提升受限于本地處理的 PHP 結果的速度?方法有多種。要說有什么不同的話,這些方法不如清單 1 中的面向套接字的方法有名。造成這種情況的原因有很多,包括:

  大多數(shù) PHP 頁面已經(jīng)足夠快 —— 更好的性能會是一種優(yōu)勢,但是還不值得對新代碼進行投入。
在 Web 頁面中使用 PHP 可以放棄部分無關緊要的性能提升 —— 當惟一的價值標準是交付整個 Web 頁面需要的時間時,那么重新安排計算以更快地獲得中間結果并不重要。

  PHP 不能控制本地瓶頸 —— 用戶可能會為花 8 秒的時間提取帳戶記錄的詳細信息而抱怨,但是那很可能是數(shù)據(jù)庫處理或某種其他 PHP 外部資源的約束。即使將 PHP 處理降至零,單是查找就仍需要花費超過 7 秒的時間。

  甚至很少有約束是并行的 —— 假定某特定頁面將為具體列出的普通股計算建議交易價格,并且計算十分復雜,需要花費一段時間。計算在本質上可能是順序執(zhí)行的。沒有一種明顯的方法可以將其劃分為 “團隊協(xié)作”。

  很少有 PHP 程序員能夠認識到 PHP 實現(xiàn)并發(fā)的潛力。在具有使用并行實現(xiàn)性能需求的少數(shù)人當中,我遇到的大多數(shù)人全都說 PHP “不支持線程”,并且甘于使用現(xiàn)有的計算模型。

  可是,有時我們可以做得更好。假定 PHP 頁面需要計算兩只股票價格,可能還需要將兩者相比較,并且底層主機剛好是多處理器。在這種情況下,通過將兩個截然不同并且十分耗時的計算分配給不同處理器,可能會提高幾乎兩倍的性能。

  在所有 PHP 計算領域中,此類實例很少見。但是,由于我發(fā)現(xiàn)到處都沒有對它的精確記錄,因此需要在這里包括用于此類加速的模型。

  清單 5. 延遲服務器實現(xiàn)

<?php
echo "Program starts at ". date('h:i:s') . ".\n";

$timeout=10;
$streams=array();
$handles=array();

/* First launch a program with a delay of three seconds, then
one which returns after only one second. */
$delay=3;
for ($id=0; $id <= 1; $id++) {
 $error_log="/tmp/error" . $id . ".txt"
 $descriptorspec=array(
  0 => array("pipe", "r"),
  1 => array("pipe", "w"),
  2 => array("file", $error_log, "w")
 );
 $cmd='sleep ' . $delay . '; echo "Finished with delay of ' .
 $delay . '".';
 $handles[$id]=proc_open($cmd, $descriptorspec, $pipes);
 $streams[$id]=$pipes[1];
 $all_pipes[$id]=$pipes;
 $delay -= 2;
}

while (count($streams)) {
 $read=$streams;
 stream_select($read, $w=null, $e=null, $timeout);
 foreach ($read as $r) {
  $id=array_search($r, $strea**ms);
  echo stream_get_contents($all_pipes[$id][1]);
  if (feof($r)) {
   fclose($all_pipes[$id][0]);
   fclose($all_pipes[$id][1]);
   $return_value=proc_close($handles[$id]);
   unset($streams[$id]);
  }
 }
}
?>

  此程序將生成如下輸出:

Program starts at 10:28:41.
Finished with delay of 1.
Finished with delay of 3.

  這里的關鍵在于 PHP 啟動了兩個獨立子進程,取回待完成的第一個進程的輸出,然后取回第二個進程的輸出,即使后者啟動得較早。如果主機是多處理器計算機,并且操作系統(tǒng)已正確配置,則操作系統(tǒng)本身負責將各個子程序分配給不同的處理器。這是在多處理器主機中良好應用 PHP 的一種方法。

  PHP 支持多任務。PHP 不按照諸如 java 編程語言或 C++ 等其他語言所采用的方法支持線程,但是以上示例表明 PHP 具有更多的超乎想象的加速潛力。

該文章在 2012/3/16 10:20:48 編輯過
關鍵字查詢
相關文章
正在查詢...
點晴ERP是一款針對中小制造業(yè)的專業(yè)生產(chǎn)管理軟件系統(tǒng),系統(tǒng)成熟度和易用性得到了國內(nèi)大量中小企業(yè)的青睞。
點晴PMS碼頭管理系統(tǒng)主要針對港口碼頭集裝箱與散貨日常運作、調度、堆場、車隊、財務費用、相關報表等業(yè)務管理,結合碼頭的業(yè)務特點,圍繞調度、堆場作業(yè)而開發(fā)的。集技術的先進性、管理的有效性于一體,是物流碼頭及其他港口類企業(yè)的高效ERP管理信息系統(tǒng)。
點晴WMS倉儲管理系統(tǒng)提供了貨物產(chǎn)品管理,銷售管理,采購管理,倉儲管理,倉庫管理,保質期管理,貨位管理,庫位管理,生產(chǎn)管理,WMS管理系統(tǒng),標簽打印,條形碼,二維碼管理,批號管理軟件。
點晴免費OA是一款軟件和通用服務都免費,不限功能、不限時間、不限用戶的免費OA協(xié)同辦公管理系統(tǒng)。
Copyright 2010-2025 ClickSun All Rights Reserved

主站蜘蛛池模板: 精品一区二区三区免费视频 | 很黄很黄地在床视频女 | 国产一区二区三区日韩精品 | 日本欧美一区二区三区不卡 | 亚洲h成年动漫在线观看不卡 | 在线观看国产精品一区 | 黑人巨大精品欧美一区在线 | 亚洲国产福利成人一区二区 | 日本高清不卡aⅴ免费网站 精品国产污 | 亚洲一区中文字幕 | 国产日韩免费视 | 国自产拍偷拍福利精品免费 | 五月社区免费 | 亚洲中文娱乐网在线观看 | 国产激情a∨在线视频播放 国产激情自拍亚洲精品国产精品精 | 精品免费播放视频 | 国产在线精品一区二区高清 | 一区②区三区电影网 | 综合精品三级亚洲 | 亚洲性色精品一区二区在线 | 国产主播福利在线观看 | 成人国产亚洲精品a区天堂 激情五月天深爱网 | 69精品人伦一区二区三区 | 日本中文字 | 国产精品日韩精品 | 国产性爱在 | 欧美日韩精品一区二区在线播放 | 亚洲加勒 | 99精品国产福利片在线观看 | 亚洲日韩在线观看免费视频 | 国产亚洲一区二区三区在线 | 野花日本大全免费 | 国产精品免费αv视频 | 亚洲欧美乱伦日本 | 亚洲春色一区 | 国产黄在线观看免费观看网站不卡 | 日韩欧美性爱视频网站翘臀 | 中文字幕与| 亚洲高清乱码午夜电影网 | 歐美性猛交xxxx亂大交3 | 国产v综合v亚洲欧美大天堂 |