php多進程插入數據(pcntl 學習筆記二)

我的在虛擬機centos7,單核,1G內存mysql

/**
 * 模擬併發請求,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;執行結果以下:sql

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時,執行結果以下:centos

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,相對來講,是挺慢的了。三分鐘。。。yii2

不過,本人再fork 1000個進程,來插入10萬記錄時,成功的狀況下36秒左右,也可能會出現錯誤,mysqli_connection返回false,是否是鏈接數受限制了?session

fork 一萬個子進程,插入一百萬數據,這時,出現鏈接錯的狀況就不少了。最後耗時360秒,數據表中插入了945300條記錄,成功率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這裏。
能夠經過一個鏈接池來嘗試解決該問題。yii

相關文章
相關標籤/搜索