未加星标

PHP多线程模拟实现秒杀抢单

字体大小 | |
[开发(php) 所属分类 开发(php) | 发布者 店小二03 | 时间 | 作者 红领巾 ] 0人收藏点击收藏

应集团要求给服务号做了个抢单秒杀的功能,需要对秒杀做个测试,想试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' );

测试代码机器性能(开发机):

PHP多线程模拟实现秒杀抢单

订单代码机器性能(测试机):

PHP多线程模拟实现秒杀抢单

系统测试结果:

模拟 1000 并发的情况,单机每秒 300+ 订单,服务器毫无压力。
反倒是测试机受不了了,CPU 飙升 100%。 Apache 偶尔崩溃。

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。


您可能感兴趣的文章:yii框架redis结合php实现秒杀效果(实例代码)php结合redis实现高并发下的抢购、秒杀功能的实例PHP+JS实现的商品秒杀倒计时用法示例php解决抢购秒杀抽奖等大流量并发入库导致的库存负数的问题PHP 类商品秒杀计时实现代码浅谈PHP实现大流量下抢购方案PHP通过加锁实现并发情况下抢码功能基于PHP实现假装商品限时抢购繁忙的效果php+redis实现商城秒杀功能

本文开发(php)相关术语:php代码审计工具 php开发工程师 移动开发者大会 移动互联网开发 web开发工程师 软件开发流程 软件开发工程师

主题: PHPWindowsCPU服务器CUOPTUTTIPython限时抢购
tags: gt,curl,PHP,result,id,url,EOL,array,logPath,flag,urls,params,function,data,thread
分页:12
转载请注明
本文标题:PHP多线程模拟实现秒杀抢单
本站链接:https://www.codesec.net/view/572603.html


1.凡CodeSecTeam转载的文章,均出自其它媒体或其他官网介绍,目的在于传递更多的信息,并不代表本站赞同其观点和其真实性负责;
2.转载的文章仅代表原创作者观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,本站对该文以及其中全部或者部分内容、文字的真实性、完整性、及时性,不作出任何保证或承若;
3.如本站转载稿涉及版权等问题,请作者及时联系本站,我们会及时处理。
登录后可拥有收藏文章、关注作者等权限...
技术大类 技术大类 | 开发(php) | 评论(0) | 阅读(124)