Yar是并行的RPC框架(Concurrent RPC framework),Laruence开发。
yar全部可用版本见:https://pecl.php.net/package/yar,根据自己的需要下载编译安装即可。
注:yar和PHP版本不一致会导致编译失败,如果出现编译失败请下载其他版本的yar重新编译
# wget https://pecl.php.net/get/yar-1.2.3.tgz
# tar -xf yar-1.2.3.tgz
# cd yar-1.2.3
# ls
config.m4 LICENSE tests yar.c yar_exception.c yar_packager.h yar_request.c yar_response.h yar_transport.c
config.w32 packagers tools yar_client.c yar_exception.h yar_protocol.c yar_request.h yar_server.c yar_transport.h
CREDITS php_yar.h transports yar_client.h yar_packager.c yar_protocol.h yar_response.c yar_server.h
# ls /usr/local/php/php7/bin/
pear peardev pecl phar phar.phar php php-cgi php-config phpdbg phpize
# /usr/local/php/php7/bin/phpize
Configuring for:
PHP Api Version: 20170718
Zend Module Api No: 20170718
Zend Extension Api No: 320170718
# ./configure --with-php-config=/usr/local/php/php7/bin/php-config
# make && make install
................
............
Installing shared extensions: /usr/local/php/php7/lib/php/extensions/no-debug-non-zts-20170718/
# ls /usr/local/php/php7/lib/php/extensions/no-debug-non-zts-20170718/
mongodb.so opcache.a opcache.so openssl.so pcntl.so phalcon.so redis.so swoole.so xhprof.so yaf.so yar.so zlib.so
我是PHP5.6 ,我的这个文件在/usr/local/php/etc这个目录下,不同版本的PHP该文件所在的位置可能会有不同。
在文件末尾追加以下内容就行:
extension=/usr/local/php/php7/lib/php/extensions/no-debug-non-zts-20170718/yar.so
或者直接:
extension=yar.so
憨憨们注意了,我的php.ini原文件是这样的,相信你们的也差不多:
[XXX];
If openssl.cafile is not specified or if the CA file is not found, the
; directory pointed to by openssl.capath is searched for a suitable
; certificate. This value must be a correctly hashed certificate directory.
; Most users should not specify a value for this directive as PHP will
; attempt to use the OS-managed cert stores in its absence. If specified,
; this value may still be overridden on a per-stream basis via the "capath"
; SSL stream context option.
;openssl.capath=
; Local Variables:
; tab-width: 4
;End:
仔细看到这里的童靴应该和我一样,是第一次接触PHP这个垃圾语言脚本语言,中Java的毒已久的我还以为配置文件里面的英文分号“;”是该文件特有的分隔符号,于是我追加成下面这样了:
; Local Variables:
; tab-width: 4
; extension=yar.so //end是结束的意思,那必须要放在那之前啊,你有分号我也写上分号,照着你的格式来 [手动捂脸]
; End:
注意了,人家的这个分号是注释键!相当于:
Java的"//“和”/* 注释的内容*/",
JS 的"//",
HTML的"<!- 注释的内容 ->"
python的“#”,
shell 的“#”。
所以要这么配置:
; Local Variables:
; tab-width: 4
; End:
extension=yar.so //分号开头的是人家注释掉的内容,我们不管,直接在文末追加你的内容即可。
执行 php --ri yar 命令,查看输出:
[root@localhost default]# php --ri yar
yar
yar support => enabled
Version => 1.2.3
Directive => Local Value => Master Value
yar.packager => php => php
yar.transport => curl => curl
yar.debug => Off => Off
yar.expose_info => On => On
yar.connect_timeout => 1000 => 1000
yar.timeout => 5000 => 5000
yar.content_type => application/octet-stream => application/octet-stream
yar.allow_persistent => 0 => 0
[root@localhost default]#
如果你的输出类似我上面的输出,那么你的yar就是安装成功的,否则安装失败。
至此yar安装完成
摘自于yar框架的作者鸟哥的文章:https://www.laruence.com/2012/09/15/2779.html
Server端(server.php):
<?php
class API {
/**
* the doc info will be generated automatically into service info page.
* @params
* @return
*/
public function api($parameter, $option = "foo") {
echo "hello world ! ";
}
protected function client_can_not_see() {
}
}
$service = new Yar_Server(new API());
$service->handle();
?>
访问:http://yourip/server.php 我们就会看到如下的接口文档:
Yar Server: API
+API::api($parameter, $option = 'foo')
没看见也不要慌,比如我刚开始就没看见这个,网上绝大多都是这个例子抄来抄去 的,但是却极少有人说看不到咋办。试试下面这个:
Client端也很简单,有2种:
1)串行:
<?php
$client = new Yar_Client("http://host/server.php");
$result = $client->api("parameter);
?>
2)并行化调用
<?php
function callback($retval, $callinfo) {
var_dump($retval);
}
Yar_Concurrent_Client::call("http://host/api/", "api", array("parameters"), "callback");
Yar_Concurrent_Client::call("http://host/api/", "api", array("parameters"), "callback");
Yar_Concurrent_Client::call("http://host/api/", "api", array("parameters"), "callback");
Yar_Concurrent_Client::call("http://host/api/", "api", array("parameters"), "callback");
Yar_Concurrent_Client::loop(); //send
?>
这样, 所有的请求会一次发出, 只要有任何一个请求完成, 回调函数”callback”就会被立即调用.
这里还有一个细节, Yar见缝插针的不会浪费任何时间, 在这些请求发送完成以后, Yar会调用一次callback, 和普通的请求返回回调不同, 这次的调用的$callinfo参数为空.
server端:yar.php
<?php
class API {
/**
* the doc info will be generated automatically into service info page.
* @params
* @return
*/
public function test() {
sleep(1);
return 't';
}
public function test2() {
sleep(3);
return 'test2';
}
}
?>
$service = new Yar_Server(new API());
$service->handle();
直接在浏览器打开http://localhost/yar.php会显示API文档。
client端:yar_client.php
<?php
//串行调用
//$client = new Yar_Client("http://localhost/yar.php");
//$client->test();
//$client->test2();
function callback($retval, $callinfo) {
//var_dump($retval);
error_log(time().':callinfo:'.json_encode($callinfo).PHP_EOL, 3, 't.log');
if ($callinfo == NULL) {
//做本地的逻辑
//return TRUE;
error_log(time().':'.'send req success'.PHP_EOL, 3, 't.log');
}else{
error_log(time().':'.$retval.PHP_EOL, 3, 't.log');
}
}
function callback2($retval, $callinfo) {
}
function error_callback($type, $error, $callinfo) {
error_log($error);
}
//并行调用:
//1、所有请求发送成功,Yar会调用一次callback,其中$callinfo为null
//2、每个请求执行完成,获取到了结果,也会去调用callback,其中$callinfo不为null
$res = Yar_Concurrent_Client::call("http://localhost/yar.php", "test");
$res1 = Yar_Concurrent_Client::call("http://localhost/yar.php", "test2");
$res2 = Yar_Concurrent_Client::loop("callback", "error_callback"); //send
?>
t.log:
1472832899:callinfo:null
1472832899:send req success
1472832900:callinfo:{"sequence":1,"uri":"http:\/\/localhost\/yar.php","method":"test"}
1472832900:t
1472832902:callinfo:{"sequence":2,"uri":"http:\/\/localhost\/yar.php","method":"test2"}
1472832902:test2
log验证了yar的执行过程。那么,实际应用中,我们就可以先发送请求, 请求发送完毕,然后得到第一次回调($callinfo为null), 继续做我们当前进程的工作; 等所有工作结束以后, 再交给Yar去获取并行RPC的响应:
<?php
function callback($retval, $callinfo) {
if ($callinfo == NULL) {
//请求发送完毕,会运行到这里
//做本地的逻辑
return TRUE;
}
//RPC请求返回, callback会再次调用。返回值在$retval
}
实际项目里,Server端里为避免每次实例化当前类,可以写个父类:
<?php
/**
*Yar控制器类
*/
class YarAction{
/**
* 架构函数
* @access public
*/
public function __construct() {
//判断扩展是否存在
if(!extension_loaded('yar'))
die('yar not support');
//实例化Yar_Server
$server = new Yar_Server($this);
// 启动server
$server->handle();
}
}
参考资料:https://www.cnblogs.com/52fhy/p/5836065.html,感谢原文作者的无私分享。