本篇文章主要介绍了PHP并发查询MySQL的实例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
最近在研究PHP,很喜欢,碰到PHP并发查询MySQL的问题,研究了一下,顺便留个笔记:
同步查询
这是我们最常的调用模式,客户端调用Query[函数],发起查询命令,等待结果返回,读取结果;再发送第二条查询命令,等待结果返回,读取结果。总耗时,会是两次查询的时间之和。简化一下过程,例如下图:
例图,由1.1到1.3为一个Query[函数]的调用,两次查询,就要串行经历1.1、1.2、1.3、2.1、2.2、2.3,尤其在1.2和2.2会阻塞等待,进程没法做其他事情。
同步调用的好处是,符合我们的直观思维,调用和处理都简单。缺点是进程阻塞在等待结果返回,增加额外的运行时间。
如果,有多条查询请求,或者进程还有其他的事情处理,那么能否把等待的时间也合理利用起来,提高进程的处理能力呢,显然是可以的。
拆分
现在,我们把Query[函数]打碎,客户端在1.1后,马上返回,客户端跳过1.2,在1.3有数据达到后再去读取数据。这样进程在原来的1.2阶段就解放了,可以做更多的事情,例如…再发起一条sql查询[2.1],是否看到了并发查询的雏形了。
并发查询
相对于同步查询的下一条查询的发起都在上一条完成后,并发查询,可以在上一条查询请求发起后,立刻发起下一条查询请求。简化一下过程,下图:
例图,在1.1.1成功发送完请求后,立马返回[1.1.2],最终查询结果的返回时在遥远的1.2 。但是在,1.1.1到1.2中间,还发起了另一个查询请求,这时间段内,就同时发起了两条查询请求,2.2先于1.2到达,那么两条查询的总耗时,只相当于第一条查询的时间。
并发查询的优点是,可以提高进程的使用率,避免阻塞等待服务器处理查询,缩短了多条查询的耗时。但缺点也很明显,发起N条并发查询,就需要建立N条数据库链接,对于有数据库连接池的应用来说,可以避免这种情况。
退化
理想情况下,我们希望并发N条查询,总耗时等于查询时间最长的一条查询。但也有可能并发查询会[退化]为[同步查询]。What?例图中,如果1.2在2.1.1前就返回了,那么并发查询就[退化]为[同步查询]了,但付出的代价却比同步查询要高。
多路复用
发起query1
发起query2
发起query3
………
等待query1、query2、query3
读取query2结果
读取query1结果
读取query3结果
那么,怎么等待知道什么时候查询结果返回了,又是哪个的查询结果返回呢?
对每个查询IO调用read?如果是遇上阻塞IO,这样就会阻塞在一个IO上,其他IO有结果返回了,也没法处理。那么,如果是非阻塞IO,那不用怕会阻塞在其中一个IO上了,确实是,但又会造成不断地轮询判断,浪费CPU资源。
对于这种情况可以使用多路复用轮询多个IO。
PHP实现并发查询MySQL
PHP的mysqli(mysqlnd驱动)提供多路复用轮询IO(mysqli_poll)和异步查询(MYSQLI_ASYNC、mysqli_reap_async_query),使用这两个特性实现并发查询,示例代码:
<?php $sqls = array( 'SELECT * FROM `mz_table_1` LIMIT 1000,10', 'SELECT * FROM `mz_table_1` LIMIT 1010,10', 'SELECT * FROM `mz_table_1` LIMIT 1020,10', 'SELECT * FROM `mz_table_1` LIMIT 10000,10', 'SELECT * FROM `mz_table_2` LIMIT 1', 'SELECT * FROM `mz_table_2` LIMIT 5,1' ); $links = []; $tvs = microtime(); $tv = explode(' ', $tvs); $start = $tv[1] * 1000 + (int)($tv[0] * 1000); // 链接数据库,并发起异步查询 foreach ($sqls as $sql) { $link = mysqli_connect('127.0.0.1', 'root', 'root', 'dbname', '3306'); $link->query($sql, MYSQLI_ASYNC); // 发起异步查询,立即返回 $links[$link->thread_id] = $link; } $llen = count($links); $process = 0; do { $r_array = $e_array = $reject = $links; // 多路复用轮询IO if(!($ret = mysqli_poll($r_array, $e_array, $reject, 2))) { continue; } // 读取有结果返回的查询,处理结果 foreach ($r_array as $link) { if ($result = $link->reap_async_query()) { print_r($result->fetch_row()); if (is_object($result)) mysqli_free_result($result); } else { } // 操作完后,把当前数据链接从待轮询集合中删除 unset($links[$link->thread_id]); $link->close(); $process++; } foreach ($e_array as $link) { die; } foreach ($reject as $link) { die; } }while($process < $llen); $tvs = microtime(); $tv = explode(' ', $tvs); $end = $tv[1] * 1000 + (int)($tv[0] * 1000); echo $end - $start,PHP_EOL;
mysqli_poll源码:
#ifndef PHP_WIN32 #define php_select(m, r, w, e, t) select(m, r, w, e, t) #else #include "win32/select.h" #endif /* {{{ mysqlnd_poll */ PHPAPI enum_func_status mysqlnd_poll(MYSQLND **r_array, MYSQLND **e_array, MYSQLND ***dont_poll, long sec, long usec, int * desc_num) { struct timeval tv; struct timeval *tv_p = NULL; fd_set rfds, wfds, efds; php_socket_t max_fd = 0; int retval, sets = 0; int set_count, max_set_count = 0; DBG_ENTER("_mysqlnd_poll"); if (sec < 0 || usec < 0) { php_error_docref(NULL, E_WARNING, "Negative values passed for sec and/or usec"); DBG_RETURN(FAIL); } FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); // 从所有mysqli链接中获取socket链接描述符 if (r_array != NULL) { *dont_poll = mysqlnd_stream_array_check_for_readiness(r_array); set_count = mysqlnd_stream_array_to_fd_set(r_array, &rfds, &max_fd); if (set_count > max_set_count) { max_set_count = set_count; } sets += set_count; } // 从所有mysqli链接中获取socket链接描述符 if (e_array != NULL) { set_count = mysqlnd_stream_array_to_fd_set(e_array, &efds, &max_fd); if (set_count > max_set_count) { max_set_count = set_count; } sets += set_count; } if (!sets) { php_error_docref(NULL, E_WARNING, *dont_poll ? "All arrays passed are clear":"No stream arrays were passed"); DBG_ERR_FMT(*dont_poll ? "All arrays passed are clear":"No stream arrays were passed"); DBG_RETURN(FAIL); } PHP_SAFE_MAX_FD(max_fd, max_set_count); // select轮询阻塞时间 if (usec > 999999) { tv.tv_sec = sec + (usec / 1000000); tv.tv_usec = usec % 1000000; } else { tv.tv_sec = sec; tv.tv_usec = usec; } tv_p = &tv; // 轮询,等待多个IO可读,php_select是select的宏定义 retval = php_select(max_fd + 1, &rfds, &wfds, &efds, tv_p); if (retval == -1) { php_error_docref(NULL, E_WARNING, "unable to select [%d]: %s (max_fd=%d)", errno, strerror(errno), max_fd); DBG_RETURN(FAIL); } if (r_array != NULL) { mysqlnd_stream_array_from_fd_set(r_array, &rfds); } if (e_array != NULL) { mysqlnd_stream_array_from_fd_set(e_array, &efds); } // 返回可操作的IO数量 *desc_num = retval; DBG_RETURN(PASS); }
并发查询操作结果
为了更直观地看效果,我找了一个1.3亿数据量并且没有优化过的表进行操作。
并发查询的结果:
同步查询的结果:
从结果来看,同步查询的总耗时是所有查询的时间的累加;而并发查询的总耗时在这里其实是查询时间最长的那一条(同步查询的第四条,耗时是10几秒,符合并发查询的总耗时),而且并发查询的查询顺序和结果到达的顺序是不一样的。
多条耗时较短的查询对比
使用多条查询时间较短的sql进行对比一下
并发查询的测试1结果(数据库链接时间也统计进去):
同步查询的结果(数据库链接时间也统计进去):
并发查询的测试2结果(不统计数据库链接时间):
从结果上看,并发查询测试1并没有讨到好处。从同步查询上看,每条查询耗时大概3-4ms左右。但如果不把数据库链接时间统计进去(同步查询只有一次数据库链接),并发查询的优势又能体现出来了。
结语
这里探讨了一下PHP实现并发查询MySQL,从实验上结果直观地认识了并发查询的优缺点。建立数据库连接的时间在一条优化了的sql查询上,占得比重还是很大。#没有连接池,要你何用
以上是php并发之关于查询MySQL的示例(图)的详细内容。更多信息请关注PHP中文网其他相关文章!

PHP在现代Web开发中仍然重要,尤其在内容管理和电子商务平台。1)PHP拥有丰富的生态系统和强大框架支持,如Laravel和Symfony。2)性能优化可通过OPcache和Nginx实现。3)PHP8.0引入JIT编译器,提升性能。4)云原生应用通过Docker和Kubernetes部署,提高灵活性和可扩展性。

PHP适合web开发,特别是在快速开发和处理动态内容方面表现出色,但不擅长数据科学和企业级应用。与Python相比,PHP在web开发中更具优势,但在数据科学领域不如Python;与Java相比,PHP在企业级应用中表现较差,但在web开发中更灵活;与JavaScript相比,PHP在后端开发中更简洁,但在前端开发中不如JavaScript。

PHP和Python各有优势,适合不同场景。1.PHP适用于web开发,提供内置web服务器和丰富函数库。2.Python适合数据科学和机器学习,语法简洁且有强大标准库。选择时应根据项目需求决定。

PHP是一种广泛应用于服务器端的脚本语言,特别适合web开发。1.PHP可以嵌入HTML,处理HTTP请求和响应,支持多种数据库。2.PHP用于生成动态网页内容,处理表单数据,访问数据库等,具有强大的社区支持和开源资源。3.PHP是解释型语言,执行过程包括词法分析、语法分析、编译和执行。4.PHP可以与MySQL结合用于用户注册系统等高级应用。5.调试PHP时,可使用error_reporting()和var_dump()等函数。6.优化PHP代码可通过缓存机制、优化数据库查询和使用内置函数。7

PHP成为许多网站首选技术栈的原因包括其易用性、强大社区支持和广泛应用。1)易于学习和使用,适合初学者。2)拥有庞大的开发者社区,资源丰富。3)广泛应用于WordPress、Drupal等平台。4)与Web服务器紧密集成,简化开发部署。

PHP在现代编程中仍然是一个强大且广泛使用的工具,尤其在web开发领域。1)PHP易用且与数据库集成无缝,是许多开发者的首选。2)它支持动态内容生成和面向对象编程,适合快速创建和维护网站。3)PHP的性能可以通过缓存和优化数据库查询来提升,其广泛的社区和丰富生态系统使其在当今技术栈中仍具重要地位。

在PHP中,弱引用是通过WeakReference类实现的,不会阻止垃圾回收器回收对象。弱引用适用于缓存系统和事件监听器等场景,需注意其不能保证对象存活,且垃圾回收可能延迟。

\_\_invoke方法允许对象像函数一样被调用。1.定义\_\_invoke方法使对象可被调用。2.使用$obj(...)语法时,PHP会执行\_\_invoke方法。3.适用于日志记录和计算器等场景,提高代码灵活性和可读性。


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

MinGW - 适用于 Windows 的极简 GNU
这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。

螳螂BT
Mantis是一个易于部署的基于Web的缺陷跟踪工具,用于帮助产品缺陷跟踪。它需要PHP、MySQL和一个Web服务器。请查看我们的演示和托管服务。

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用