PHP教程之奇妙处理PHP没法完成多线程的成绩
开发相册系统过程中就有过这样的问题,因为没有交流好,出现重复工作问题,因为文档没有详细的说明而经常临时问对方。 有无举措在PHP中完成多线程呢?假定你正在写一个基于多台办事器的PHP使用,幻想的情形时同时向多台办事器发送恳求,而不是一台接一台。可以完成吗?当有人想要完成并发功效时,他们凡是会想到用fork或spawn threads,然而当他们发明PHP不撑持多线程的时分,也许会转换思绪去用一些不敷好的言语,好比Perl。其实的是大多半情形下,你大可不用利用fork或线程,而且你会失掉比用fork或thread更好的功能。假定你要创立一个办事来反省正在运转的n台办事器,以肯定他们还在正常运转。你能够会写上面如许的代码:
[*] $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中的处理办法:
[*] $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_CONNECTSTREAM_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()来创立毗连:
[*] // 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 ($rsocket_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程序了,虽然离职业和专业的人还有很远,但是好的开始是成功的一半。这个时候改怎么做了呢。现在就是拿1本高手推荐的书,重头到尾读1遍,我说的这个读是自己看。 首先我是坚决反对新手上来就用框架的,因为对底层的东西一点都不了解,造成知识上的真空,会对以后的发展不利。我的观点上手了解下框架就好,代码还是手写。当然啦如果是位别的编程语言的高手的话,这个就另当别论啦。 再就是混迹于论坛啦,咱们的phpchina的论坛就很强大,提出的问题一般都是有达人去解答的,以前的帖子也要多看看也能学到不少前辈们的经验。别的不错的论坛例如php100,javaeye也是很不错的。 要进行开发,搭建环境是首先需要做的事,windows下面我习惯把环境那个安装在C盘下面,因为我配的环境经常出现诡异事件,什么事都没做环境有的时候就不能用啦。 使用zendstdio 写代码的的时候,把tab 的缩进设置成4个空格是很有必要的 建数据库表的时候,int型要输入长度的,其实是个摆设的输入几位都没影响的,只要大于4就行,囧。 本人接触php时间不长,算是phper中的小菜鸟一只吧。由于刚开始学的时候没有名师指,碰过不少疙瘩,呗很多小问题卡过很久,白白浪费不少宝贵的时间,在次分享一些子的学习的心得。 写的比较杂,因为我也是个新手,不当至于大家多多指正。 Ps:以上纯属原创,如有雷同,纯属巧合 在学习的过程中不能怕麻烦,不能有懒惰的思想。学习php首先应该搭建一个lamp环境或者是wamp环境。这是学习php开发的根本。虽然网络上有很多集成的环境,安装很方便,使用起来也很稳定、 找到的的资料很多都是在论坛里的,需要注册,所以我一般没到一个论坛都注册一个id,所有的id都注册成一样的,这样下次再进来的时候就不用重复注册啦。当然有些论坛的某些资料是需要的付费的。 当然这种网站的会员费就几十块钱。 因为blog这样的可以让你接触更多要学的知识,可以接触用到类,模板,js ,ajax php里的数组为空的时候是不能拿来遍历的;(这个有点低级啊,不过我刚被这个边界问题墨迹了好长一会) 使用zendstdio 写代码的的时候,把tab 的缩进设置成4个空格是很有必要的 装在C盘下面可以利用windows的ghost功能可以还原回来(顺便当做是重转啦),当然啦我的编译目录要放在别的盘下,不然自己的劳动成果就悲剧啦。 找到的的资料很多都是在论坛里的,需要注册,所以我一般没到一个论坛都注册一个id,所有的id都注册成一样的,这样下次再进来的时候就不用重复注册啦。当然有些论坛的某些资料是需要的付费的。 遇到出错的时候,我经常把错误信息直接复制到 google的搜索栏,一般情况都是能搜到结果的,不过有时候会搜出来一大片英文的出来,这时候就得过滤一下,吧中文的弄出来,挨着式方法。 真正的方向了,如果将来要去开发团队,你一定要学好smarty ,phplib这样的模板引擎, 本人接触php时间不长,算是phper中的小菜鸟一只吧。由于刚开始学的时候没有名师指,碰过不少疙瘩,呗很多小问题卡过很久,白白浪费不少宝贵的时间,在次分享一些子的学习的心得。
页:
[1]
2