加入收藏 | 设为首页 | 会员中心 | 我要投稿 汽车网 (https://www.0577qiche.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长学院 > PHP教程 > 正文

PHP多线程模拟实现秒杀操作

发布时间:2023-09-23 11:00:36 所属栏目:PHP教程 来源:
导读:应集团要求给服务号做了个抢单秒杀的功能,需要对秒杀做个测试,想试试PHP多线程,就模拟了下抢单功能。

先说秒杀模块的思路:

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

1、发起秒杀请求

2、进入秒杀队列

3、随机滞
应集团要求给服务号做了个抢单秒杀的功能,需要对秒杀做个测试,想试试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( !emptyempty($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( emptyempty($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( emptyempty($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'], 
  );//Cuoxin.com 

insertList( $urls_array, './query.log' ); 
系统测试结果:

模拟 1000 并发的情况,单机每秒 300+ 订单,服务器毫无压力。

反倒是测试机受不了了,CPU 飙升 100%。 Apache 偶尔崩溃。

不知道是 PHP 多线程和 Windows 环境的支持不好,还是 PHP 多线程本身的问题,区区 1000 线程跑不动。多线程的地方还是比较需要 Python 和 C 出马。

(编辑:汽车网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章