php在并发处理方面的确不如java好。但是也有一些方法可以实现并发处理。比如使用curl就可以实现url的并发请求。
看到网上有人说使用curl会导致阻塞,即所有的请求数据都获取完毕后一并返回,然后再进行数据处理。而不是获取一个请求的数据就处理一个数据。其实这种说法是不对的,只能说明他在代码实现上有问题。
在php官方找了段导致阻塞的示例代码,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | function multiple_threads_request( $nodes ){ $mh = curl_multi_init(); $curl_array = array (); foreach ( $nodes as $i => $url ) { $curl_array [ $i ] = curl_init( $url ); curl_setopt( $curl_array [ $i ], CURLOPT_RETURNTRANSFER, true); curl_multi_add_handle( $mh , $curl_array [ $i ]); } $running = NULL; do { usleep(10000); curl_multi_exec( $mh , $running ); } while ( $running > 0); $res = array (); foreach ( $nodes as $i => $url ) { $res [ $url ] = curl_multi_getcontent( $curl_array [ $i ]); } foreach ( $nodes as $i => $url ){ curl_multi_remove_handle( $mh , $curl_array [ $i ]); } curl_multi_close( $mh ); return $res ; } print_r(muti_thread_request( array ( 'http://www.example.com' , 'http://www.example.net' , ))); |
下面是边请求url,边处理返回数据的示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | /* * @purpose: 使用curl并行处理url * @return: array 每个url获取的数据 * @param: $urls array url列表 * @param: $callback string 需要进行内容处理的回调函数。示例:func(array) */ function curl( $urls = array (), $callback = '' ) { $response = array (); if ( empty ( $urls )) { return $response ; } $chs = curl_multi_init(); $map = array (); foreach ( $urls as $url ){ $ch = curl_init(); curl_setopt( $ch , CURLOPT_URL, $url ); curl_setopt( $ch , CURLOPT_TIMEOUT, 1); curl_setopt( $ch , CURLOPT_RETURNTRANSFER, 1); curl_setopt( $ch , CURLOPT_HEADER, 0); curl_setopt( $ch , CURLOPT_NOSIGNAL, true); curl_multi_add_handle( $chs , $ch ); $map [ strval ( $ch )] = $url ; } do { if (( $status = curl_multi_exec( $chs , $active )) != CURLM_CALL_MULTI_PERFORM) { if ( $status != CURLM_OK) { break ; } //如果没有准备就绪,就再次调用curl_multi_exec while ( $done = curl_multi_info_read( $chs )) { $info = curl_getinfo( $done [ "handle" ]); $error = curl_error( $done [ "handle" ]); $result = curl_multi_getcontent( $done [ "handle" ]); $url = $map [ strval ( $done [ "handle" ])]; $rtn = compact( 'info' , 'error' , 'result' , 'url' ); if (trim( $callback )) { $callback ( $rtn ); } $response [ $url ] = $rtn ; curl_multi_remove_handle( $chs , $done [ 'handle' ]); curl_close( $done [ 'handle' ]); //如果仍然有未处理完毕的句柄,那么就select if ( $active > 0) { curl_multi_select( $chs , 0.5); //此处会导致阻塞大概0.5秒。 } } } } while ( $active > 0); //还有句柄处理还在进行中 curl_multi_close( $chs ); return $response ; } //使用方法 function deal( $data ){ if ( $data [ "error" ] == '' ) { echo $data [ "url" ]. " -- " . $data [ "info" ][ "http_code" ]. "\n" ; } else { echo $data [ "url" ]. " -- " . $data [ "error" ]. "\n" ; } } $urls = array (); for ( $i = 0; $i < 10; $i ++) { $urls [] = 'http://www.baidu.com/s?wd=etao_' . $i ; $urls [] = 'http://www.so.com/s?q=etao_' . $i ; $urls [] = 'http://www.soso.com/q?w=etao_' . $i ; } curl( $urls , "deal" ); |
演示网址 http://demo.bo56.com/bigpipe/
注释:
1.关于curl_multi_exec函数的返回值:
返回CURLM_CALL_MULTI_PERFORM 说明curl_multi_exec需要马上被再调用一次。
返回CURLM_OK 说明已经有需要处理的数据。这时你需要进行相关处理,处理完后再次调用curl_multi_exec。
php中的curl_multi_exec是调用的curl库中的curl_multi_perform方法。代码在multi.c的230行左右。
2.此方式,虽然在获取数据和数据处理上是并行的,但是在数据处理时依然是串行的。即数据是一条条依次处理的。如果deal方法比较耗时的话,那整体会非常耗时。
技术交流

原文链接:php实现并发处理之curl篇,转载请注明来源!