<kbd id='woaibaidu'></kbd><address id='woaibaidu'><style id='woaibaidu'></style></address><button id='woaibaidu'></button>

          当前位置:主页 > 网络编程 > PHP编程 >
            PHP多线程模拟实现秒杀抢单
            2018-02-12 22:03 发布 次浏览

          应团体要求给效劳号做了个抢单秒杀的功用,需求对秒杀做个测试,想试试PHP多线程,就模仿了下抢单功用。

          先说秒杀模块的思绪:

          正常状况下的用户秒杀操作

          1、提倡秒杀恳求
          2、进入秒杀行列
          3、随机滞后 1 - 2 秒停止秒杀后果查询恳求(算是变相分流吧)
          4、乐成则生成定单
          5、前往后果

          以下是模仿秒杀的代码:

          <?php
          
          
          set_time_limit(0);
          
          /**
          * 线程的履行义务
          */
          class Threadrun extends Thread
          {
            public $url;
            public $data;
            public $params;
          
            public function __construct($url, $params=[])
            {
             $this->url = $url;
             $this->params = $params;
            }
          
            public function run()
            {
             if(($url = $this->url))
             {
               $params = [
                'goods_id'  => 1,
                'activity_id'  => 1,
                'user_id'   => isset($this->params['user_id']) ? $this->params['user_id'] : $this->getCurrentThreadId(),
               ];
               $startTime = microtime(true);
               $this->data = [
                'id'   => $params['user_id'],
                'result'  => model_http_curl_get( $url, $params ),
                'time'  => microtime(true)-$startTime,
                'now'   => microtime(true),
               ];
             }
            }
          }
          
          /**
          * 履行多线程
          */
          function model_thread_result_get($urls_array)
          {
            foreach ($urls_array as $key => $value)
            {
             $threadPool[$key] = new Threadrun($value["url"],['user_id'=>$value['user_id']]);
             $threadPool[$key]->start();
            }
            foreach ($threadPool as $thread_key => $thread_value)
            {
             while($threadPool[$thread_key]->isRunning())
             {
               usleep(10);
             }
             if($threadPool[$thread_key]->join())
             {
               $variable_data[$thread_key] = $threadPool[$thread_key]->data;
             }
            }
            return $variable_data;
          }
          
          /**
          * 发送 HTTP 恳求
          */
          function model_http_curl_get($url,$data=[],$userAgent="")
          {
            $userAgent = $userAgent ? $userAgent : 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2)';
            $curl = curl_init();
            curl_setopt($curl, CURLOPT_URL, $url);
            curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($curl, CURLOPT_TIMEOUT, 5);
            curl_setopt($curl, CURLOPT_USERAGENT, $userAgent);
            curl_setopt($curl, CURLOPT_POST, true);
            if( !empty($data) ) {
             curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
            }
            $result = curl_exec($curl);
            curl_close($curl);
            return $result;
          }
          
          
          /**
           * 敌对的打印变量
           * @param $val
           */
          function dump( $val )
          {
            echo '<pre>';
            var_dump($val);
            echo '</pre>';
          }
          
          /**
           * 写日志
           * @param $msg
           * @param string $logPath
           */
          function writeLog( $msg, $logPath='' ) {
            if( empty($logPath) ) {
             $logPath = date('Y_m_d').'.log';
            }
            if( !file_exists($logPath) ) {
             $fp = fopen( $logPath,'w' );
             fclose( $fp );
            }
            error_log( $msg.PHP_EOL, 3, $logPath);
          }
          
          /**
           * 生成日志信息
           * @param $result
           * @param $timeDiff
           * @return bool|string
           */
          function createLog( $result, $timeDiff ){
            if( empty($result) || !is_array($result) ) {
             return false;
            }
            $succeed = 0;
            $fail = 0;
            foreach( $result as $v ) {
             $times[] = $v['time'];
             $v['result'] === false ? $fail++ : $succeed++;
            }
            $totalTime = array_sum( $times );
            $maxTime = max( $times );
            $minTime = min( $times );
            $sum = count( $times );
            $avgTime = $totalTime/$sum;
            $segment = str_repeat('=',100);
            $flag = $segment . PHP_EOL;
            $flag .= '总共履行工夫:' . $timeDiff . PHP_EOL ;
            $flag .= '最大履行工夫:' . $maxTime . PHP_EOL;
            $flag .= '最小履行工夫:' . $minTime . PHP_EOL;
            $flag .= '均匀恳求工夫:' . $avgTime . PHP_EOL;
            $flag .= '恳求数:' . $sum . PHP_EOL;
            $flag .= '恳求乐成数:' . $succeed . PHP_EOL;
            $flag .= '恳求失败数:' . $fail . PHP_EOL;
            $flag .= $segment . PHP_EOL;
            return $flag;
          
          }
          
          
          /**
           * 提倡秒杀恳求
           */
          function insertList( $urls, $logPath='' )
          {
            $t = microtime(true);
            $result = model_thread_result_get($urls);
            $e = microtime(true);
            $timeDiff = $e-$t;
            echo "总履行工夫:" . $timeDiff . PHP_EOL;
            foreach( $result as $v ) {
             $msg = '用户【' . $v['id'] . '】秒杀商品, 前往后果 ' . $v['result'] . ' 用时【' . $v['time'] . ' 秒】 以后工夫【'.$v['now'].'】';
             writeLog( $msg,$logPath );
            }
            $logStr = createLog( $result, $timeDiff);
            writeLog( $logStr, $logPath );
            return $result;
          }
          
          
          //提倡秒杀恳求
          for ($i=0; $i < 1000; $i++)
          {
            $urls_array[] = array("name" => "baidu", "url" => "http://***.***.com/seckill/shopping/listinsert");
          }
          
          $list = insertList( $urls_array, './inset.log' );
          
          //提倡秒杀后果查询恳求
          $urls_array = [];
          foreach( $list as $v ) {
            if( $v['result'] === false ) {
             continue;
            }
            $urls_array[] = array(
                  "name"  => "baidu",
                  "url"  => "http://***.***.com/seckill/shopping/query",
                  'user_id' => $v['id'],
            );
          }
          insertList( $urls_array, './query.log' );
          
          

          测试代码机械功能(开发机):

          定单代码机械功能(测试机):

          零碎测试后果:

          模仿 1000 并发的状况,单机每秒 300+ 定单,效劳器毫无压力。
          反倒是测试机受不了了,CPU 飙升 100%。 Apache 偶然解体。

          不晓得是 PHP 多线程和 Windows 情况的支持欠好,照旧 PHP 多线程自身的成绩,区区 1000 线程跑不动。多线程的中央照旧比拟需求 Python 和 C 出马。

          以上就是本文的全部内容,希望对各人的学习有所协助,也希望各人多多支持聚合网。