php 使用swoole多進程執行任務,避免mysql has gone away

swoole多進程處理數據速度很快,但是會遇到mysql has gone away的情況需要小心:

Mysql.php:

<?php

class Mysql
{

    private $host;

    private $user;

    private $password;

    private $charset;

    private $database;

    /**
     * 新建數據庫連接對象,測試數據庫連接
     *
     * @param string $host
     * @param string $user
     * @param string $password
     * @param string $charset
     * @param string $database
     */
    function __construct($host, $user, $password, $charset, $database)
    {
        $link = mysqli_connect($host, $user, $password) or die('數據庫連接失敗<br />ERROR ' . mysqli_connect_errno() . ':' . mysqli_connect_error());
        $char = mysqli_set_charset($link, $charset) or die('charset設置錯誤,請輸入正確的字符集名稱<br />ERROR ' . mysqli_errno($link) . ':' . mysqli_error($link));
        $db = mysqli_select_db($link, $database) or die('未找到數據庫,請輸入正確的數據庫名稱<br />ERROR ' . mysqli_errno($link) . ':' . mysqli_error($link));
        $this->host = $host;
        $this->user = $user;
        $this->password = $password;
        $this->charset = $charset;
        $this->database = $database;
        mysqli_close($link);
    }

    /**
     * 連接數據庫
     *
     * @param string $host
     * @param string $user
     * @param string $password
     * @param string $charset
     * @param string $database
     * @return object 連接標識符
     */
    public function connect($host = '', $user = '', $password = '', $charset = '', $database = '')
    {
        $link = mysqli_connect($this->host, $this->user, $this->password);
        mysqli_set_charset($link, $this->charset);
        mysqli_select_db($link, $this->database);
        return $link;
    }

    /**
     * 增加數據
     *
     * @param array $data
     * @param string $table
     * @return boolean
     */
    public function insert($data, $table,$link = '')
    {
        if(empty($link)){

            $link = $this->connect($this->host, $this->user, $this->password, $this->charset, $this->database);
        }
        $keys = join(',', array_keys($data));
        $vals = "'" . join("','", array_values($data)) . "'";
        $query = "INSERT INTO {$table}({$keys}) VALUES({$vals})";
        $result = mysqli_query($link, $query) or die('插入數據出錯,請檢查!<br />ERROR ' . mysqli_errno($link) . ':' . mysqli_error($link));
        if ($result) {
            $id = mysqli_insert_id($link);
        } else {
            $id = false;
        }
        mysqli_close($link);
        return $id;
    }

    /**
     * 刪除數據
     *
     * @param string $table
     * @param string $where
     * @return boolean
     */
    public function delete($table, $where = null,$link = '')
    {
        if(empty($link)){
            $link = $this->connect($this->host, $this->user, $this->password, $this->charset, $this->database);
        }
        $where = $where ? ' WHERE ' . $where : '';
        $query = "DELETE FROM {$table}{$where}";
        $result = mysqli_query($link, $query) or die('刪除數據出錯,請檢查!<br />ERROR ' . mysqli_errno($link) . ':' . mysqli_error($link));
        if ($result) {
            $row = mysqli_affected_rows($link);
        } else {
            $row = false;
        }
        mysqli_close($link);
        return $row;
    }

    /**
     * 修改數據
     *
     * @param array $data
     * @param string $table
     * @param string $where
     * @return boolean
     */
    public function update($data, $table, $where = null,$link = '')
    {
        if(empty($link)) {
            $link = $this->connect($this->host, $this->user, $this->password, $this->charset, $this->database);
        }
        $set = '';
        foreach ($data as $key => $val) {
            $set .= "{$key}='{$val}',";
        }
        $set = trim($set, ',');
        $where = $where ? ' WHERE ' . $where : '';
        $query = "UPDATE {$table} SET {$set}{$where}";
        $result = mysqli_query($link, $query);
        if ($result) {
            $row = mysqli_affected_rows($link);
        } else {
            $row = false;
        }
        mysqli_close($link);
        return $row;
    }

    /**
     * 查詢指定記錄
     *
     * @param string $query
     * @param string $result_type
     * @return array|boolean
     */
    public function select_one($query, $result_type = MYSQLI_ASSOC,$link = '')
    {
        if(empty($link)) {

            $link = $this->connect($this->host, $this->user, $this->password, $this->charset, $this->database);
        }
        $result = mysqli_query($link, $query);
        if ($result && mysqli_num_rows($result) > 0) {
            $row = mysqli_fetch_array($result, $result_type);
        } else {
            $row = false;
        }
        mysqli_free_result($result);
        mysqli_close($link);
        return $row;
    }

    /**
     * 查詢所有記錄
     *
     * @param string $query
     * @param string $result_type
     * @return array|boolean
     */
    public function select_all($query, $result_type = MYSQLI_ASSOC,$link = '')
    {
        if(empty($link)){

            $link = $this->connect($this->host, $this->user, $this->password, $this->charset, $this->database);
        }
        // $query = "SELECT * FROM {$table}";
        $result = mysqli_query($link, $query);
        if ($result && mysqli_num_rows($result) > 0) {
            while ($row = mysqli_fetch_array($result, $result_type)) {
                $rows[] = $row;
            }
        } else {
            $rows = false;
        }
        mysqli_free_result($result);
        mysqli_close($link);
        return $rows;
    }

    /**
     * 得到表中記錄數
     *
     * @param string $table
     * @return number|boolean
     */
    public function get_total_rows($table)
    {
        $link = $this->connect($this->host, $this->user, $this->password, $this->charset, $this->database);
        $query = "SELECT COUNT(*) AS totalRows FROM {$table}";
        $result = mysqli_query($link, $query);
        if ($result && mysqli_num_rows($result) == 1) {
            $row = mysqli_fetch_assoc($result);
        } else {
            $row['totalRows'] = false;
        }
        mysqli_close($link);
        return $row['totalRows'];
    }
}
PageUtils.php
class PageUtils {

    public static $countpage;
    /**
     * 數組分頁函數  核心函數  array_slice
     * 用此函數之前要先將數據庫裏面的所有數據按一定的順序查詢出來存入數組中
     * $count   每頁多少條數據
     * $page   當前第幾頁
     * $array   查詢出來的所有數組
     * order 0 - 不變     1- 反序
     */

    public static function page_array($count,$page,$array,$order){
        global $countpage; #定全局變量
        $page=(empty($page))?'1':$page; #判斷當前頁面是否爲空 如果爲空就表示爲第一頁面
        $start=($page-1)*$count; #計算每次分頁的開始位置
        if($order==1){
            $array=array_reverse($array);
        }
        $totals=count($array);
        self::$countpage=ceil($totals/$count); #計算總頁面數
        $pagedata=array();
        $pagedata=array_slice($array,$start,$count);
        return $pagedata;  #返回查詢數據
    }


}

swoole多進程循環執行任務demo代碼:

<?php
/**
 *
 * swoole 多進程循環處理數據
 * 適用cli腳本
 *
 */

include 'Mysql.php';
include 'PageUtils.php';

class cli_run{

    public function process_demo()
    {

        echo '當前佔用內存大小:' . memory_get_usage()/1024 . "kb\n";
        //數據庫
        $mysql = new Mysql('數據庫鏈接', '帳號','密碼','utf8','數據庫名稱');
        $min_id = 0;
        $flag = false;
        $redirectStdout = false;
        do{

            $workers = array();
            $flag = false;
            $all_PicList = $mysql->select_all("SELECT * FROM table WHERE id > {$min_id} AND  status = 1 limit 1000");

            if(empty($all_PicList)){

                die('finish');
            }

            $limit = 100;
            $all_page = ceil(count($all_PicList)/$limit);
            //分10 個進程,每個進程執行100條數據
            for ($i = 1;$i<=$all_page;$i++){

                $picList = PageUtils::page_array($limit,$i,$all_PicList,0);
                $process = new swoole_process(function (swoole_process $worker) use ($picList,$mysql) {

                    foreach ($picList as $v){

                        //邏輯處理


                        $mysql->select_one('');
                        $mysql->update('');
                    }

                    $worker->exit(0);

                },$redirectStdout);

                //執行fork系統調用,啓動進程
                $pid = $process->start();
                // 進程重命名
                $process->name('cli_run_'.$pid);
                // 將每一個進程的句柄存起來
                $workers[$pid] = $process;
                $process = null;

            }

            if (count($picList) > 0) {
                // 監控/回收子進程
                while (1) {
                    $ret = \swoole_process::wait();
                    if ($ret) { // $ret 是個數組 code是進程退出狀態碼,
                        $pid = $ret['pid'];
                        echo "Worker Exit, PID=" . $pid . PHP_EOL;
                    } else {
                        $last = array_slice($all_PicList,-1,1);
                        //獲取最後一個最大的id,繼續循環直到數據沒有
                        $min_id = $last[0]['id'];
                        echo '當前佔用內存大小:' . memory_get_usage()/1024 . "kb\n";
                        $flag = true;
                        break;
                    }
                }
            }

        }while($flag);

    }

}

 

把大量數據先進行limit定量獲取,再把取出的數據分配到各個進程去處理任務,縮短了數據處理的時間,比起while(1)單進程任務速度快百倍。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章