php开发桌面应用程序_使用PHP V5开发多任务应用程序

php开发桌面应用程序

PHP不支持线程。 尽管如此,与我与之交谈的大多数PHP开发人员所相信的相反,PHP应用程序可以执行多任务。 让我们首先尽可能清楚地了解“多任务”和“线程”对PHP编程的意义。

各种并发

首先是搁置一些与主题相切的案例。 PHP与多任务或并发有着复杂的关系。 在高层次上,PHP是不断涉及多任务 :服务器端PHP的标准安装-作为Apache模块,例如-在一个多任务的方式使用 。 也就是说,几个客户端(Web浏览器)可以同时请求一个用PHP解释的页面,然后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') . ".\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.

了解这里发生的事情很重要。 在较高的层次上,第一个程序发出几个HTTP请求并接收Web服务器发送的页面。 虽然生产应用程序可能会访问多个Web服务器-可能是google.com,yahoo.com,ask.com等,但此示例将其所有请求发送到Phaseit.net上的公司服务器,只是为了降低复杂性。

可变延迟后请求的网页返回结果,如下所示。 如果程序按顺序发出请求,则大约需要15 + 12 + 9 + 6 + 3(45)秒才能完成。 如清单2所示,它实际上在15秒内完成。 三倍性能很棒。

PHP V5的新stream_select函数使之成为可能。 通过打开几个stream_socket_client并向与http://phaseit.net/demonstration/delay?delay=$DELAY相对应的每个GET写入一个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来说没有负担。 这是不寻常的跨网络程序运行freadwhile在这样一种方式,CPU使用率缩放到100%。 这里不是这种情况,因为stream_select具有理想的属性,只要有可能进行任何读取,它就会立即响应,但是在两次读取之间等待时,它表示的CPU负载可以忽略不计。

关于stream_select()几点了解

这样的基于事件的编程不是基本的。 尽管清单1简化为基本内容,但是涉及回调或协调的任何编码(对于多任务应用程序都是必需的)将比简单的过程序列更不熟悉。 在这种情况下,大多数挑战都集中在$read数组上。 注意这是一个参考 ; stream_select通过更改$read的内容返回关键信息。 就像指针已成为C的最大绊脚石一样,引用似乎是PHP的一部分,给程序员带来了最大的困难。

您可以使用此技术从任意数量的外部网站请求请求,确信您的程序将尽快收到每个结果,而无需等待其他请求。 实际上,相同的技术可以正确处理任何TCP / IP连接,而不仅仅是与Web端口80的连接,因此,从原则上讲,您可以管理LDAP检索,SMTP传输,SOAP请求等。

但这还不是全部。 PHP V5将各种连接管理为“流”,而不仅仅是简单的套接字。 PHP的客户端URL库(CURL)支持HTTPS证书,FTP上传,Cookie等。 (CURL允许PHP应用程序使用各种协议来连接服务器。)由于CURL提供了流接口,因此从程序角度看,连接是透明的。 下一部分显示stream_select如何甚至复用本地计算。

stream_select也会伴随一些注意事项。 它的文档不足,即使最近PHP书籍也没有涵盖它。 Web上的几个代码示例根本不起作用或令人困惑。 stream_select的第二个和第三个参数管理与清单1中的已read通道相对应的write通道和exception通道,几乎应始终为null。 除少数例外,在可写或特殊通道上进行选择是错误的。 除非您有经验,否则请遵循可读的选择。

同样, stream_select中的错误至少要迟到PHP V5.1.2。 最关键的是,该函数的返回值是不可信的。 尽管尚未调试实现,但我的经验是,尽管有官方文档,但可以像清单1一样安全地测试count($read) ,但不能安全地返回stream_select本身的返回值。

本地PHP并发

上面的示例和大部分讨论都集中于如何同时管理多个远程资源并在它们到达时接收结果,而不是等待按照原始请求的顺序处理每个资源。 这当然是PHP并发的重要用途。 实际应用有时可以加速10倍或更多。

如果经济放缓离家近呢? 有没有一种方法可以加快受本地处理限制PHP结果? 有几个。 如果有的话,它们甚至比清单1的面向套接字的方法还不为人所知。其原因有很多,其中包括:

  • 大多数PHP页面都足够快-更好的性能将是一个优点,但不足以值得在新代码上进行投资。
  • PHP在Web页面中的使用可能使部分加速变得无关紧要-重新排序计算以使中间结果更快可用并不重要,因为唯一的优点是交付整个Web页面需要花费多长时间。
  • 很少有本地瓶颈在PHP的控制之下-用户可能会抱怨,从帐户记录中提取详细信息需要8秒钟,但这很可能是数据库处理或PHP外部其他资源的限制。 即使我们将PHP处理量减少为零,仅查找所需的时间仍将超过7秒。
  • 甚至更少的约束是可以并行化的-假设特定页面计算了特定上市普通股的建议交易价格,并且计算非常复杂,需要很多秒。 该计算可能本质上是顺序的。 没有明显的方法将其划分为“团队合作”。
  • 很少有PHP程序员了解PHP的并发潜力。 在少数几个具有并行化性能要求的应用程序中,我所见到的大多数情况只是简单地提到PHP“不做线程”,而将自己重归于现有的计算模型。

但是有时候我们可以做得更好。 假设一个PHP页面需要计算两个股票价格,也许是为了比较它们,而基础主机恰好是一个多处理器。 在这种情况下,通过将两个不同且耗时的计算分配给不同的处理器,我们可能使性能几乎翻倍。

在所有PHP计算中,此类实例很少见。 但是,由于我发现没有其他地方能准确记录该文件,因此我想在此包括此类提速模型。

清单5.延迟服务器实现
<?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, $streams); 
                  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启动了两个独立的子进程,检索了第一个子进程的输出以完成,然后检索了第二个子进程的输出,即使后者较早启动。 如果主机是多处理器计算机,并且操作系统配置正确,则操作系统本身负责将不同的子程序分配给不同的处理器。 这是使用PHP在多处理主机上获得优势的一种方法。

摘要

PHP多任务。 PHP不像Java™编程语言或C ++这样的其他语言支持线程化,但是以上示例表明PHP具有提速的潜力,远胜于许多人。


翻译自: https://www.ibm.com/developerworks/opensource/library/os-php-multitask/index.html

php开发桌面应用程序

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:编程工作室 设计师:CSDN官方博客 返回首页
评论
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值