您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關PHP多線程模擬如何實現秒殺搶單,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
應集團要求給服務號做了個搶單秒殺的功能,需要對秒殺做個測試,想試試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 出馬。
關于“PHP多線程模擬如何實現秒殺搶單”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。