Home >Backend Development >PHP Tutorial >Develop multi-tasking applications with PHP V5_PHP Tutorial

Develop multi-tasking applications with PHP V5_PHP Tutorial

WBOY
WBOYOriginal
2016-07-13 17:29:551074browse

许多 PHP 开发人员认为,由于标准的 PHP 缺少线程功能,因此实际 PHP 应用程序不可能执行多任务处理。例如,如果应用程序需要其他 Web 站点的信息,那么在远程检索完成之前它都必须停止。这是错误的!通过本文了解如何使用 stream_select 和 stream_socket_client 实现进程内 PHP 多任务处理。

  PHP 不支持线程。尽管如此,与前述大多数 PHP 开发人员所相信的想法形成对比的是,PHP 应用程序可以 执行多任务处理。让我们开始尽可能清晰地描述一下 “多任务” 和 “线程” 对于 PHP 编程的意义。

  并发的种类

  首先抛开几个和主题无关的例子。PHP 与多任务或并发的关系十分复杂。在较高层次上,PHP 经常涉及多任务:以多任务方式使用 标准的服务器端 PHP 安装 —— 例如,作为 Apache 模块。换句话说,若干个客户机 —— Web 浏览器 —— 可以同时请求同一个 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.0 Host: 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 停止,直至数据就绪。重要的一点是,只要任何 连接具有数据,不管顺序怎样,程序都将开始读取。这是程序进行多任务处理或并发处理来自多个请求的结果的方法。

Note that this does not place any burden on the host CPU. We often encounter some networking programs that use fread in while in such a way that the CPU usage rises rapidly to 100%. That won't happen here, because stream_select has the properties needed to support immediate response (as long as there is any read information), but it will incur negligible CPU load during the waiting time between read operations.

 Essential stream_select() knowledge

Event-based programming like this is not fundamental. Although Listing 1 is reduced to the bare essentials, any coding involving callbacks or coordination that is a necessary element of a multitasking application feels more alien than simple program sequencing. In this case, most of the challenges focus on the $read array. Note that it is a reference; stream_select will return the important information by changing the contents of $read. Just like pointers are the biggest stumbling block in C, references seem to be the most troublesome part of PHP for programmers.

You can use this technology to make requests to any number of external Web sites, confident that your program will receive all results as quickly as possible without having to wait for other requests. In fact, this technology will correctly handle all TCP/IP connections, not just those on Web port 80, so you can generally manage LDAP retrievals, SMTP transfers, SOAP requests, and more.

But that’s not all. PHP V5 will manage various connections like "streams", not just simple sockets. PHP's Client URL library (CURL) supports HTTPS certificates, FTP uploads, cookies, and more. (CURL allows PHP applications to connect to servers using various protocols). Since CURL will provide a streaming interface, the connection is transparent from the program's perspective. The next section shows how stream_select multiplexes local computations.

There are a few things to note about stream_select. It's still being documented, as even the latest PHP books don't cover it. Available on the Web

www.bkjia.comtruehttp: //www.bkjia.com/PHPjc/509212.htmlTechArticleMany PHP developers believe that since standard PHP lacks threading capabilities, it is impossible for real PHP applications to perform multitasking deal with. For example, if the application requires another website...
Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn