php多线程实现方法及用法实例详解


Posted in PHP onOctober 26, 2015

下面我们来介绍具体php多线程实现程序代码,有需要了解的同学可参考。
当有人想要实现并发功能时,他们通常会想到用fork或者spawn threads,但是当他们发现php不支持多线程的时候,大概会转换思路去用一些不够好的语言,比如perl。
其实的是大多数情况下,你大可不必使用fork 或者线程,并且你会得到比用fork 或thread 更好的性能。
假设你要建立一个服务来检查正在运行的n台服务器,以确定他们还在正常运转。你可能会写下面这样的代码:
代码如下 

<?php
$hosts = array("host1.sample.com", "host2.sample.com", "host3.sample.com");
$timeout = 15;
$status = array();
foreach ($hosts as $host) {
 $errno = 0;
 $errstr = "";
 $s = fsockopen($host, 80, $errno, $errstr, $timeout);
 if ($s) {
 $status[$host] = "Connectedn";
 fwrite($s, "HEAD / HTTP/1.0rnHost: $hostrnrn");
 do {
  $data = fread($s, 8192);
  if (strlen($data) == 0) {
  break;
  }
  $status[$host] .= $data;
 } while (true);
 fclose($s);
 } else {
 $status[$host] = "Connection failed: $errno $errstrn";
 }
}
print_r($status);
?>

它运行的很好,但是在fsockopen()分析完hostname并且建立一个成功的连接(或者延时$timeout秒)之前,扩充这段代码来管理大量服务器将耗费很长时间。
因此我们必须放弃这段代码;我们可以建立异步连接-不需要等待fsockopen返回连接状态。PHP仍然需要解析hostname(所以直接使用ip更加明智),不过将在打开一个连接之后立刻返回,继而我们就可以连接下一台服务器。
两种方法可以实现:PHP5中可以使用新增的stream_socket_client()函数直接替换掉fsocketopen()。PHP5之前的版本,你需要自己动手,用sockets扩展解决问题。
下面是PHP5中的解决方法:
代码如下

<?php
$hosts = array("host1.sample.com", "host2.sample.com", "host3.sample.com");
$timeout = 15;
$status = array();
$sockets = array();
/* Initiate connections to all the hosts simultaneously */
foreach ($hosts as $id => $host) {
 $s = stream_socket_client("
$
$host:80", $errno, $errstr, $timeout,
 STREAM_CLIENT_ASYNC_CONNECT|STREAM_CLIENT_CONNECT);
 if ($s) {
 $sockets[$id] = $s;
 $status[$id] = "in progress";
 } else {
 $status[$id] = "failed, $errno $errstr";
 }
}
/* Now, wait for the results to come back in */
while (count($sockets)) {
 $read = $write = $sockets;
 /* This is the magic function - explained below */
 $n = stream_select($read, $write, $e = null, $timeout);
 if ($n > 0) {
 /* readable sockets either have data for us, or are failed
  * connection attempts */
 foreach ($read as $r) {
   $id = array_search($r, $sockets);
   $data = fread($r, 8192);
   if (strlen($data) == 0) {
  if ($status[$id] == "in progress") {
  $status[$id] = "failed to connect";
  }
  fclose($r);
  unset($sockets[$id]);
   } else {
  $status[$id] .= $data;
   }
 }
 /* writeable sockets can accept an HTTP request */
 foreach ($write as $w) {
  $id = array_search($w, $sockets);
  fwrite($w, "HEAD / HTTP/1.0rnHost: "
  . $hosts[$id] . "rnrn");
  $status[$id] = "waiting for response";
 }
 } else {
 /* timed out waiting; assume that all hosts associated
  * with $sockets are faulty */
 foreach ($sockets as $id => $s) {
  $status[$id] = "timed out " . $status[$id];
 }
 break;
 }
}
foreach ($hosts as $id => $host) {
 echo "Host: $hostn";
 echo "Status: " . $status[$id] . "nn";
} 
?>

我们用stream_select()等待sockets打开的连接事件。stream_select()调用系统的select(2)函数来工作:前面三个参数是你要使用的streams的数组;你可以对其读取,写入和获取异常(分别针对三个参数)。stream_select()可以通过设置$timeout(秒)参数来等待事件发生-事件发生时,相应的sockets数据将写入你传入的参数。
下面是PHP4.1.0之后版本的实现,如果你已经在编译PHP时包含了sockets(ext/sockets)支持,你可以使用根上面类似的代码,只是需要将上面的streams/filesystem函数的功能用ext/sockets函数实现。主要的不同在于我们用下面的函数代替stream_socket_client()来建立连接:
代码如下 

<?php
// This value is correct for Linux, other systems have other values
define('EINPROGRESS', 115);
function non_blocking_connect($host, $port, &$errno, &$errstr, $timeout) {
 $ip = gethostbyname($host);
 $s = socket_create(AF_INET, SOCK_STREAM, 0);
 if (socket_set_nonblock($s)) {
 $r = @socket_connect($s, $ip, $port);
 if ($r || socket_last_error() == EINPROGRESS) {
  $errno = EINPROGRESS;
  return $s;
 }
 }
 $errno = socket_last_error($s);
 $errstr = socket_strerror($errno);
 socket_close($s);
 return false;
}
?>

现在用socket_select()替换掉stream_select(),用socket_read()替换掉fread(),用socket_write()替换掉fwrite(),用socket_close()替换掉fclose()就可以执行脚本了!
PHP5的先进之处在于,你可以用stream_select()处理几乎所有的stream-例如你可以通过include STDIN用它接收键盘输入并保存进数组,你还可以接收通过proc_open()打开的管道中的数据。
下面来分享一个PHP多线程类
代码如下

* @title:   PHP多线程类(Thread)
 * @version:  1.0
 * 
 * PHP多线程应用示例:
 * require_once 'thread.class.php';
 * $thread = new thread();
 * $thread->addthread('action_log','a');
 * $thread->addthread('action_log','b');
 * $thread->addthread('action_log','c');
 * $thread->runthread();
 * 
 * function action_log($info) {
 *   $log = 'log/' . microtime() . '.log';
 *   $txt = $info . "rnrn" . 'Set in ' . Date('h:i:s', time()) . (double)microtime() . "rn";
 *   $fp = fopen($log, 'w');
 *   fwrite($fp, $txt);
 *   fclose($fp);
 * }
 */
class thread {
 
  var $hooks = array();
  var $args = array();
 
  function thread() {
  }
 
  function addthread($func)
  {
    $args = array_slice(func_get_args(), 1);
    $this->hooks[] = $func;
    $this->args[] = $args;
    return true;
  }
 
  function runthread()
  {
    if(isset($_GET['flag']))
    {
      $flag = intval($_GET['flag']);
    }
    if($flag || $flag === 0)
    {
      call_user_func_array($this->hooks[$flag], $this->args[$flag]);
    }
    else
    {
      for($i = 0, $size = count($this->hooks); $i < $size; $i++)
      {
        $fp=fsockopen($_SERVER['HTTP_HOST'],$_SERVER['SERVER_PORT']);
        if($fp)
        {
          $out = "GET {$_SERVER['PHP_SELF']}?flag=$i HTTP/1.1rn";
          $out .= "Host: {$_SERVER['HTTP_HOST']}rn";
          $out .= "Connection: Closernrn";
          fputs($fp,$out);
          fclose($fp);
        }
      }
    }
  }
}

希望本文所述对大家的PHP程序设计有所帮助。

PHP 相关文章推荐
ASP和PHP都是可以删除自身的
Apr 09 PHP
PHP日期处理函数 整型日期格式
Jan 12 PHP
深入探讨PHP中的内存管理问题
Aug 31 PHP
PHP资源管理框架Assetic简介
Jun 12 PHP
PDO预处理语句PDOStatement对象使用总结
Nov 20 PHP
ThinkPHP 3.2 版本升级了哪些内容
Mar 05 PHP
windows7配置Nginx+php+mysql的详细教程
Sep 04 PHP
PHP实现APP微信支付的实例讲解
Feb 10 PHP
PHP实现PDO操作mysql存储过程示例
Feb 13 PHP
PHP 实现 WebSocket 协议原理与应用详解
Apr 22 PHP
phpStorm2020 注册码
Sep 17 PHP
一文搞懂PHP中的抽象类和接口
May 25 PHP
浅析ThinkPHP缓存之快速缓存(F方法)和动态缓存(S方法)(日常整理)
Oct 26 #PHP
PHP和C#可共用的可逆加密算法详解
Oct 26 #PHP
日常整理PHP中简单的图形处理(经典)
Oct 26 #PHP
php 参数过滤、数据过滤详解
Oct 26 #PHP
php解析url并得到url中的参数及获取url参数的四种方式
Oct 26 #PHP
php实现CSV文件导入和导出
Oct 24 #PHP
PHP错误Warning:mysql_query()解决方法
Oct 24 #PHP
You might like
php入门学习知识点一 PHP与MYSql连接与查询
2011/07/14 PHP
thinkPHP使用post方式查询时分页失效的解决方法
2015/12/09 PHP
ThinkPHP连接Oracle数据库
2016/04/22 PHP
php验证身份证号码正确性的函数
2016/07/20 PHP
用js实现的一个Flash滚动轮换显示图片代码生成器
2007/03/14 Javascript
利用js 进行输入框自动匹配字符的小例子
2013/06/29 Javascript
Jquery 复选框取值兼容FF和IE8(测试有效)
2013/10/29 Javascript
javascript判断两个IP地址是否在同一个网段的实现思路
2013/12/13 Javascript
dreamweaver 8实现Jquery自动提示
2014/12/04 Javascript
js实现同一页面可多次调用的图片幻灯切换效果
2015/02/28 Javascript
深入理解JavaScript系列(31):设计模式之代理模式详解
2015/03/03 Javascript
JQuery实现鼠标滚轮滑动到页面节点
2015/07/28 Javascript
基于jQuery ligerUI实现分页样式
2016/09/18 Javascript
bootstrap配合Masonry插件实现瀑布式布局
2017/01/18 Javascript
jQuery实现Table表格隔行变色及高亮显示当前选择行效果示例
2017/02/14 Javascript
JS设置手机验证码60s等待实现代码
2017/06/14 Javascript
jQuery实现可拖动进度条实例代码
2017/06/21 jQuery
详谈表单格式化插件jquery.serializeJSON
2017/06/23 jQuery
使用jquery Ajax实现上传附件功能
2018/10/23 jQuery
express框架中使用jwt实现验证的方法
2019/08/25 Javascript
微信提示 在浏览器打开 效果实现过程解析
2019/09/10 Javascript
稍微学一下Vue的数据响应式(Vue2及Vue3区别)
2019/11/21 Javascript
用Python编写一个简单的Lisp解释器的教程
2015/04/03 Python
Java中重定向输出流实现用文件记录程序日志
2015/06/12 Python
PyQt5实现QLineEdit添加clicked信号的方法
2019/06/25 Python
pytorch 共享参数的示例
2019/08/17 Python
Python3 hashlib密码散列算法原理详解
2020/03/30 Python
德国前卫设计师时装在线商店:Luxury Loft
2019/11/04 全球购物
Java里面如何把一个Array数组转换成Collection, List
2013/07/26 面试题
优秀技术工人先进材料
2014/02/17 职场文书
购房意向书范本
2014/04/01 职场文书
2014年最新个人对照检查材料范文
2014/09/25 职场文书
2014年幼儿园工作总结
2014/11/10 职场文书
五一劳动节活动总结
2015/02/09 职场文书
《分数乘法》教学反思
2016/02/24 职场文书
vue3种table表格选项个数的控制方法
2022/04/14 Vue.js