PHP多线程模拟实现秒杀抢单
程序员文章站
2023-02-08 10:29:31
应集团要求给服务号做了个抢单秒杀的功能,需要对秒杀做个测试,想试试php多线程,就模拟了下抢单功能。
先说秒杀模块的思路:
正常情况下的用户秒杀操作
1、发起秒杀...
应集团要求给服务号做了个抢单秒杀的功能,需要对秒杀做个测试,想试试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 出马。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
下一篇: 如果演义中荆州没丢,刘备能不能统一三国?