PHP异步并发访问mysql简单实现
在实际的开发过程中,我们常常会遇到需要操作多张表,多个库的情况。有时因为一些限制我们不能进行连表(例如,异地数据库),所以只能用php串行访问后再在php里进行合并,有时还需要模拟mysql对合并后的结果进行排序、归并等。
这里产生的一个问题就是串行带来的访问时间问题。由于传统的串行访问方式,我们只能等到一条sql执行完毕后才可以执行下一条,所以执行时间是累加的。PHP官方手册提供了一种可以异步并发访问mysql的方式,详见:http://php.net/manual/zh/mysqli.poll.php,参考资料:https://svn.osgeo.org/mapguide/sandbox/rfc94/Oem/php/ext/mysqli/tests/mysqli_poll.phpt,使用此种方式,我们可以对Mysql进行异步并发访问,访问时间不再是串行累加,而是取决于执行时间最长的sql。
项目地址:https://github.com/huyanping/async-mysql-php
show you the code:
try{
$async_mysql = new \Jenner\Mysql\Async();
$async_mysql->attach(
['host' => '127.0.0.1', 'user' => 'root', 'password' => '', 'database' => 'test'],
'select * from stu'
);
$async_mysql->attach(
['host' => '127.0.0.1', 'user' => 'root', 'password' => '', 'database' => 'test'],
'select * from stu limit 0, 3'
);
$result = $async_mysql->execute();
print_r($result);
}catch (Exception $e){
echo $e->getMessage();
}
async_mysql对象对mysql进行异步并发访问,attach方法接收每个请求必须的配置信息,execute方法为执行入口,其返回值是每条sql执行结果的数组,顺序与attach调用顺序一致。
当任何一个连接mysql出错或执行任何一条sql出错,都会引起异常抛出。这样设计主要是基于完整性的考虑,我们把所有需要执行的sql看做是一个整体事务,任何一个执行失败,则认为该事务失败。
composer信息:
"require":{
"jenner/async-mysql-php": "v0.1"
}
或者直接引入/path/to/async-mysql-php/autoload.php文件
最后在阿里云上做了一个简单的测试,测试结果如下:
# 同步
[root@iZ942077c78Z async-mysql-php]# php tests/performance_sync.php
------------------------------------------
mark:[total diff]
time:4.2648551464081s
memory_real:18944KB
memory_emalloc:18377.171875KB
memory_peak_real:28416KB
memory_peak_emalloc:27560.3828125KB
[root@iZ942077c78Z async-mysql-php]# php tests/performance_sync.php
------------------------------------------
mark:[total diff]
time:4.2285549640656s
memory_real:18944KB
memory_emalloc:18377.171875KB
memory_peak_real:28416KB
memory_peak_emalloc:27560.3828125KB
[root@iZ942077c78Z async-mysql-php]# php tests/performance_async.php
------------------------------------------
mark:[total diff]
time:1.455677986145s
memory_real:38144KB
memory_emalloc:32574.015625KB
memory_peak_real:66816KB
memory_peak_emalloc:65709.7734375KB
# 异步
[root@iZ942077c78Z async-mysql-php]# php tests/performance_async.php
------------------------------------------
mark:[total diff]
time:1.8936941623688s
memory_real:38144KB
memory_emalloc:32574.015625KB
memory_peak_real:66816KB
memory_peak_emalloc:65709.7734375KB
[root@iZ942077c78Z async-mysql-php]# php tests/performance_async.php
------------------------------------------
mark:[total diff]
time:1.5208158493042s
memory_real:38144KB
memory_emalloc:32574.015625KB
memory_peak_real:66816KB
memory_peak_emalloc:65709.7734375KB
实际上以上测试结果并没有太大意义。因为理论上这种异步并发的访问方式会绝对优于传统的串行访问方式,再次需要说明的是,访问数据库的时间接近执行时间最长的SQL。
由于同一时间要处理多个SQL返回的结果,程序需要连续申请多个内存空间用于存储SQL的返回结果。
所以使用这种方式会造成内存翻倍。从下面的测试结果来看,内存基本位置在两倍以内(测试程序执行了两条SQL)。
到了这一步,我们已经可以实现对mysql进行异步并发访问了。如果我们还需要做多个数组的归并,可以使用《PHP模拟SQL的GROUP BY算法》中介绍的方法。其中提供的归并方式非常灵活,更胜mysql原生的group by。
如果还需要对合并后的结果做排序,可以使用https://github.com/huyanping/Zebra-Tools/blob/master/src/Jenner/Zebra/Tools/CommonArray.php#L90这段代码实现,非常方便。改函数来源于php手册http://php.net/manual/zh/function.array-multisort.php
评论 (0)