PHP多線程類比實現秒殺搶單活動(附代碼)

來源:互聯網
上載者:User
這次給大家帶來PHP多線程類比實現秒殺搶單活動(附代碼),PHP多線程類比實現秒殺搶單活動的注意事項有哪些,下面就是實戰案例,一起來看一下。

先說秒殺模組的思路:

正常情況下的使用者秒殺操作

1、發起秒殺請求
2、進入秒殺隊列
3、隨機滯後 1 - 2 秒進行秒殺結果查詢請求(算是變相分流吧)
4、成功則產生訂單
5、返回結果

以下是類比秒殺的代碼:

<?phpset_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 出馬。

相信看了本文案例你已經掌握了方法,更多精彩請關注php中文網其它相關文章!

推薦閱讀:

redis計數器類使用步驟詳解

php處理搶購類高並發請求實現詳解

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.