巧妙解决P HP无法实现多线程的问题
有没有办法在PHP中实现多线程呢假设你正在写一个基于多台服务器的PHP应用理想的情况时同时向多台服务器发送请求而不是一台接一台。可以实现吗当有人想要实现并发功能时他们通常会想到用fo rk或者s pawn threa ds但是当他们发现PHP不支持多线程的时候大概会转换思路去用一些不够好的语言 比如Per l。
其实的是大多数情况下你大可不必使用for k或者线程并且你会得到比用fo rk或th read更好的性能。假设你要建立一个服务来检查正在运行的n台服务器 以确定他们还在正常运转。你可能会写下面这样的代码
1. $hosts = array("host1 .sample.com", "host2 .sample.com", "host3.sampl e.com") ;
2. $timeout = 15;
3. $status = array( ) ;
4. foreach ($hosts as $host) {
5. $errno = 0;
6. $errstr = "";
7. $s = fsockopen($host, 80, $errno, $errstr, $timeout) ;
8. if ($s) {
9. $status[$host] = "Connectedn";
10. fwrite($s, "HEAD / HTTP/1.0rnHost: $hostrnrn") ;
11. do {
12. $data = fread($s, 8192) ;
13. if (strlen($data) == 0) {
14. break;
15. }
16. $status[$host] .= $data;
17. }
18. while (true) ;
19. fclose($s) ;
20. }
21. else {
22. $status [$host] = "Connection failed: $errno $errstrn";
23. }
24. }
25.print_r($status) ;
26. ?>
它运行的很好但是在fs ockop en()分析完ho stnam e并且建立一个成功的连接或者延时$timeo ut秒之前扩充这段代码来管理大量服务器将耗费很长时间。
因此我们必须放弃这段代码我们可以建立异步连接-不需要等待fsock open返回连接状态。PHP仍然需要解析h ostna me 所以直接使用ip更加明智 不过将在打开一个连接之后立刻返回继而我们就可以连接下一台服务器。
有两种方法可以实现 PHP5中可以使用新增的str eam_s ocket_clie nt()函数直接替换掉fso cketo pen() 。PHP5之前的版本你需要自己动手用sock ets扩展解决问题。下面是PH P5中的解决方法
1. $hosts = array("host1 .sample.com", "host2 .sample.com", "host3.sampl e.com") ;
2. $timeout = 15;
3. $status = array( ) ;
4. $sockets = array( ) ;
5. /* Initiate connections to all the hosts simultaneously */
6. foreach ($hosts as $id => $host) {
7. $s = stream_socket_client("$host: 80", $errno, $errstr, $timeout,
8. STREAM_CLIENT_ASYNC_CONNECT| STREAM_CLIENT_CONNECT) ;
9. if ($s) {
10. $sockets[$id] = $s;
11. $status[$id] = "in progress";
12. }
13. else { $status[$id] = "failed, $errno $errstr";
14. }
15. }
16. /* Now, wait for the results to come back in */
17.
18.while (count($sockets) ) {
19. $read = $write = $sockets;
20. /* This is the magic function - explained below */
21. $n = stream_select($read, $write, $e = null, $timeout) ;
22. if ($n > 0) {
23. /* readable sockets either have data for us, or are failed * connection attempts */
24. foreach ($read as $r) {
25. $id = array_search($r, $sockets) ;
26. $data = fread($r, 8192) ;
27. if (strlen($data) == 0) {
28. if ($status[$id] == "in progress") {
29. $status[$id] = "failed to connect";
30. }
31. fclose($r) ;
32. unset($sockets[$id] ) ;
33. }
34. else {
35. $status[$id] .= $data;
36. }
37. }
38. /* writeable sockets can accept an HTTP request */
39. foreach ($write as $w) {
40. $id = array_search($w, $sockets) ;
41. fwrite($w, "HEAD / HTTP/1.0rnHost: "
42. . $hosts [$id] . "rnrn") ;
43. $status[$id] = "waiting for response";
44. }
45. }
46. else {
47. /* timed out waiting; assume that all hosts associated * with $sockets are faulty */
48. foreach ($sockets as $id => $s) {
49. $status[$id] = "timed out "
50. . $status[$id] ;
51. }
52.break;
53. }
54. }
55. foreach ($hosts as $id => $host) {
56. echo "Host: $hostn"; echo "Status: "
57. . $status[$id] . "nn";
58. }
59. ?>
我们用st ream_selec t()等待soc kets打开的连接事件。 strea m_sel ect()调用系统的selec t(2)函数来工作前面三个参数是你要使用的str eams的数组你可以对其读取写入和获取异常分别针对三个参数 。 stream_sel ect()可以通过设置$timeout 秒参数来等待事件发生-事件发生时相应的sockets数据将写入你传入的参数。
下面是PH P4. 1.0之后版本的实现如果你已经在编译PH P时包含了socke ts(ext/socke ts)支持你可以使用根上面类似的代码只是需要将上面的st reams/files ystem函数的功能用ext/socke ts函数实现。主要的不同在于我们用下面的函数代替stream_soc ket_c lient ()来建立连接
1. // This value is correct for Linux, other systems have other values
2. define( 'EINPROGRES S' , 115) ;
3. function non_blocking_connect($host, $port, &$errno, &$errstr, $timeout) {
4. $ip = gethostbyname($host) ;
5. $s = socket_create(AF_INET, SOCK_STREAM, 0) ;
6. if (socket_set_nonblock($s) ) {
7. $r = @socket_connect($s, $ip, $port) ;
8. if ($r | | socket_last_error( ) == EINPROGRESS) {
9. $errno = EINPROGRES S;
10. return $s;
11. }
12. }
13. $errno = socket_last_error($s) ;
14. $errstr = socket_strerror($errno) ;
15. socket_close($s) ;
16. return false;
17. }
18. ?>
现在用so cket_selec t()替换掉st ream_selec t() 用sock et_re ad()替换掉fr ead() 用sock et_wr ite()替换掉fwrite() 用sock et_cl ose()替换掉fc lose()就可以执行脚本了
PHP5的先进之处在于你可以用s tream_sele ct()处理几乎所有的str eam。例如你可以通过inc lude STDIN用它接收键盘输入并保存进数组你还可以接收通过pr oc_op en()打开的管道中的数据。
hostkey应该不用说大家都是比较熟悉的荷兰服务器品牌商家,主打荷兰、俄罗斯机房的独立服务器,包括常规服务器、AMD和Intel I9高频服务器、GPU服务器、高防服务器;当然,美国服务器也有,在纽约机房!官方网站:https://hostkey.com/gpu-dedicated-servers/比特币、信用卡、PayPal、支付宝、webmoney都可以付款!CPU类型AMD Ryzen9 ...
简介酷盾安全怎么样?酷盾安全,隶属于云南酷番云计算有限公司,主要提供高防CDN服务,高防服务器等,分为中国境内CDN,和境外CDN和二个产品,均支持SSL。目前CDN处于内测阶段,目前是免费的,套餐包0.01一个。3G流量(高防CDN)用完了继续续费或者购买升级包即可。有兴趣的可以看看,需要实名的。官方网站: :点击进入官网云南酷番云计算有限公司优惠方案流量3G,用完了不够再次购买或者升级套餐流量...
提速啦(www.tisula.com)是赣州王成璟网络科技有限公司旗下云服务器品牌,目前拥有在籍员工40人左右,社保在籍员工30人+,是正规的国内拥有IDC ICP ISP CDN 云牌照资质商家,2018-2021年连续4年获得CTG机房顶级金牌代理商荣誉 2021年赣州市于都县创业大赛三等奖,2020年于都电子商务示范企业,2021年于都县电子商务融合推广大使。资源优势介绍:Ceranetwo...