個人在虛擬機器centos7,單核,1G記憶體
/** * 模拟并发请求,10万次写入数据库 * 拆分为10个进程,每个进程处理一万条插入 */ $total = 10000; $num = 10; $per = $total/$num; $sql = ''; $child = ''; echo 'start '.microtime(true).PHP_EOL; for($i = 1; $i<= $num; $i++) { $pid = pcntl_fork(); if($pid == -1) { die('fork error'); } if($pid > 0) { //$id = pcntl_wait($status,WNOHANG); $child[] = $pid; } else if ($pid == 0) { $link = mysqli_connect('localhost','root','root','yii2advanced'); $start = ($i-1)*$per + 1; $end = $start + $per; for($j = $start; $j< $end; $j++){ $time = microtime(true); $sql = 'insert pcntl_test (rank,time) values ('.$j.','.$time.')'; mysqli_query($link,$sql); } mysqli_close($link); $id = getmypid(); echo 'child '.$id.' finished '.microtime(true).PHP_EOL; exit(0); } } while(count($child)){ foreach($child as $k => $pid) { $res = pcntl_waitpid($pid, $status, WNOHANG); if ( -1 == $res || $res > 0) { unset($child[$k]); } } } echo 'end '.microtime(true).PHP_EOL;
當$total=10000,$num = 10;執行結果如下:
start 1491903371.5548 child 19860 finished 1491903417.2113 child 19857 finished 1491903417.6909 child 19864 finished 1491903417.7793 child 19855 finished 1491903417.8695 child 19859 finished 1491903417.9162 child 19861 finished 1491903418.0089 child 19856 finished 1491903418.0532 child 19863 finished 1491903418.0842 child 19862 finished 1491903418.1474 child 19858 finished 1491903418.4341 end 1491903418.4424 总时间为46.88759994506836秒
當$total=10000,$ num = 100時,執行結果如下:
start 1491904334.1735 child 20085 finished 1491904337.0712 child 20086 finished 1491904337.144 …… child 20262 finished 1491904341.5602 child 20264 finished 1491904341.5803 end 1491904341.5869 总时间为7.413399934768677
當$total=10000,$num = 1000時,執行結果如下:
start 1491904562.0166 child 20282 finished 1491904562.1191 child 20277 finished 1491904562.1268 child 20279 finished 1491904562.1352 ... child 21586 finished 1491904576.6954 child 21582 finished 1491904576.7024 child 21584 finished 1491904576.7226 end 1491904576.7297 总时间为14.71310019493103,相比100个子进程,耗时更长了。进程切换太多,影响了了效率应该是原因之一。
當$total=100000 ,$num=100時,十萬筆記錄,100個進程插入
start 1491905670.2652 child 21647 finished 1491905725.4382 child 21651 finished 1491905725.4595 child 21642 finished 1491905725.5402 .... child 21810 finished 1491905729.7709 child 21812 finished 1491905729.8498 child 21811 finished 1491905729.9612 end 1491905729.9679 总时间为59.70270013809204
單一進程插入1萬個數據,耗時18秒,相對10個進程插入1萬個記錄來說,耗時少一點。
而單進程插入10萬筆記錄,耗時187.40066790581,相對來說,是挺慢的了。三分鐘。 。 。
不過,本人再fork 1000個進程,來插入10萬記錄時,成功的情況下36秒左右,也可能會出現錯誤,mysqli_connection返回false,是不是連線數受限了?
fork 一萬個子進程,插入一百萬個數據,這時,出現連接錯的情況就很多了。最後耗時360秒,在資料表中插入了945,300筆記錄,成功率94.53%。於是查看資料庫的相關設定資訊
mysql> show global status like '%connect%'; +-----------------------------------------------+---------------------+ | Variable_name | Value | +-----------------------------------------------+---------------------+ | Aborted_connects | 0 | | Connection_errors_accept | 0 | | Connection_errors_internal | 0 | | Connection_errors_max_connections | 628 | | Connection_errors_peer_address | 0 | | Connection_errors_select | 0 | | Connection_errors_tcpwrap | 0 | | Connections | 16519 | | Locked_connects | 0 | | Max_used_connections | 501 | | Max_used_connections_time | 2017-04-12 15:19:54 | | Performance_schema_session_connect_attrs_lost | 0 | | Ssl_client_connects | 0 | | Ssl_connect_renegotiates | 0 | | Ssl_finished_connects | 0 | | Threads_connected | 4 | +-----------------------------------------------+---------------------+ mysql> show global variables like '%connect%'; +-----------------------------------------------+--------------------+ | Variable_name | Value | +-----------------------------------------------+--------------------+ | character_set_connection | utf8mb4 | | collation_connection | utf8mb4_general_ci | | connect_timeout | 10 | | disconnect_on_expired_password | ON | | init_connect | | | max_connect_errors | 100 | | max_connections | 500 | | max_user_connections | 0 | | performance_schema_session_connect_attrs_size | 512 | +-----------------------------------------------+--------------------+ 修改 myqsql 配置文件,/etc/my.cnf 把max_connections 改为10000,然后重启mysql 实际MySQL服务器允许的最大连接数16384; 结果然并卵,虚拟机好像挂了了。
並發量大的時候,問題就出在連接mysql這裡了。
可以透過一個連線池來嘗試解決該問題。
個人在虛擬機器centos7,單核,1G記憶體
/** * 模拟并发请求,10万次写入数据库 * 拆分为10个进程,每个进程处理一万条插入 */ $total = 10000; $num = 10; $per = $total/$num; $sql = ''; $child = ''; echo 'start '.microtime(true).PHP_EOL; for($i = 1; $i<= $num; $i++) { $pid = pcntl_fork(); if($pid == -1) { die('fork error'); } if($pid > 0) { //$id = pcntl_wait($status,WNOHANG); $child[] = $pid; } else if ($pid == 0) { $link = mysqli_connect('localhost','root','root','yii2advanced'); $start = ($i-1)*$per + 1; $end = $start + $per; for($j = $start; $j< $end; $j++){ $time = microtime(true); $sql = 'insert pcntl_test (rank,time) values ('.$j.','.$time.')'; mysqli_query($link,$sql); } mysqli_close($link); $id = getmypid(); echo 'child '.$id.' finished '.microtime(true).PHP_EOL; exit(0); } } while(count($child)){ foreach($child as $k => $pid) { $res = pcntl_waitpid($pid, $status, WNOHANG); if ( -1 == $res || $res > 0) { unset($child[$k]); } } } echo 'end '.microtime(true).PHP_EOL;
當$total=10000,$num = 10;執行結果如下:
start 1491903371.5548 child 19860 finished 1491903417.2113 child 19857 finished 1491903417.6909 child 19864 finished 1491903417.7793 child 19855 finished 1491903417.8695 child 19859 finished 1491903417.9162 child 19861 finished 1491903418.0089 child 19856 finished 1491903418.0532 child 19863 finished 1491903418.0842 child 19862 finished 1491903418.1474 child 19858 finished 1491903418.4341 end 1491903418.4424 总时间为46.88759994506836秒
當$total= 10000,$num = 100時,執行結果如下:
start 1491904334.1735 child 20085 finished 1491904337.0712 child 20086 finished 1491904337.144 …… child 20262 finished 1491904341.5602 child 20264 finished 1491904341.5803 end 1491904341.5869 总时间为7.413399934768677
當$total=10000,$num = 1000時,執行結果如下:
start 1491904562.0166 child 20282 finished 1491904562.1191 child 20277 finished 1491904562.1268 child 20279 finished 1491904562.1352 ... child 21586 finished 1491904576.6954 child 21582 finished 1491904576.7024 child 21584 finished 1491904576.7226 end 1491904576.7297 总时间为14.71310019493103,相比100个子进程,耗时更长了。进程切换太多,影响了了效率应该是原因之一。
當$total=100000 ,$num =100時,十萬筆記錄,100個進程插入
start 1491905670.2652 child 21647 finished 1491905725.4382 child 21651 finished 1491905725.4595 child 21642 finished 1491905725.5402 .... child 21810 finished 1491905729.7709 child 21812 finished 1491905729.8498 child 21811 finished 1491905729.9612 end 1491905729.9679 总时间为59.70270013809204
單一進程插入1萬筆數據,耗時18秒,相對10個進程插入1萬筆記錄來說,耗時少一點。
而單進程插入10萬筆記錄,耗時187.40066790581,相對來說,是挺慢的了。三分鐘。 。 。
不過,本人再fork 1000個進程,來插入10萬記錄時,成功的情況下36秒左右,也可能會出現錯誤,mysqli_connection返回false,是不是連線數受限了?
fork 一萬個子進程,插入一百萬個數據,這時,出現連接錯的情況就很多了。最後耗時360秒,在資料表中插入了945,300筆記錄,成功率94.53%。於是查看資料庫的相關設定資訊
mysql> show global status like '%connect%'; +-----------------------------------------------+---------------------+ | Variable_name | Value | +-----------------------------------------------+---------------------+ | Aborted_connects | 0 | | Connection_errors_accept | 0 | | Connection_errors_internal | 0 | | Connection_errors_max_connections | 628 | | Connection_errors_peer_address | 0 | | Connection_errors_select | 0 | | Connection_errors_tcpwrap | 0 | | Connections | 16519 | | Locked_connects | 0 | | Max_used_connections | 501 | | Max_used_connections_time | 2017-04-12 15:19:54 | | Performance_schema_session_connect_attrs_lost | 0 | | Ssl_client_connects | 0 | | Ssl_connect_renegotiates | 0 | | Ssl_finished_connects | 0 | | Threads_connected | 4 | +-----------------------------------------------+---------------------+ mysql> show global variables like '%connect%'; +-----------------------------------------------+--------------------+ | Variable_name | Value | +-----------------------------------------------+--------------------+ | character_set_connection | utf8mb4 | | collation_connection | utf8mb4_general_ci | | connect_timeout | 10 | | disconnect_on_expired_password | ON | | init_connect | | | max_connect_errors | 100 | | max_connections | 500 | | max_user_connections | 0 | | performance_schema_session_connect_attrs_size | 512 | +-----------------------------------------------+--------------------+ 修改 myqsql 配置文件,/etc/my.cnf 把max_connections 改为10000,然后重启mysql 实际MySQL服务器允许的最大连接数16384; 结果然并卵,虚拟机好像挂了了。
並發量大的時候,問題就出在連接mysql這裡了。
可以透過一個連線池來嘗試解決該問題。
以上是php多進程插入數據的詳細內容。更多資訊請關注PHP中文網其他相關文章!