PHP多线程模拟实现秒杀抢单
发布:smiling 来源: PHP粉丝网 添加日期:2018-10-11 12:55:42 浏览: 评论: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( !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'],
- );//phpfensi.com
- }
- insertList( $urls_array, './query.log' );
系统测试结果:
模拟 1000 并发的情况,单机每秒 300+ 订单,服务器毫无压力。
反倒是测试机受不了了,CPU 飙升 100%。 Apache 偶尔崩溃。
不知道是 PHP 多线程和 Windows 环境的支持不好,还是 PHP 多线程本身的问题,区区 1000 线程跑不动。多线程的地方还是比较需要 Python 和 C 出马。
Tags: 线程
相关文章
- ·PHP线程安全和非线程安全版本的区别(2013-12-08)
- ·PHP Curl多线程实现原理与实例详解(2014-01-09)
- ·php中CURL实现多线程的笔记(2014-06-18)
- ·php多线程thread开发与应用的例子(2014-06-25)
- ·PHP多线程(pthreads)参数传递学习笔记(2014-06-27)
- ·PHP多线程(pthreads)与自动加载BUG问题(2014-08-27)
- ·php多线程抓取信息测试例子(2014-08-27)
- ·PHP多线程的实现方法详解(2014-08-27)
- ·PHP中实现异步调用多线程程序代码(2014-08-28)
- ·php多线程的几点思考(2015-04-08)
- ·php基于Socket实现多线程开发教程(2015-04-15)
- ·php异步多线程swoole使用实例程序(2015-04-15)
- ·PHP多线程pthreads使用例子(2015-12-24)
- ·PHP多进程之pcntl_fork的实例详解(2018-09-13)
- ·php curl_multi 多线程查询的例子(2018-09-16)
- ·php多线程并发是怎么实现的(2018-09-18)
推荐文章
热门文章
最新评论文章
- 写给考虑创业的年轻程序员(10)
- PHP新手上路(一)(7)
- 惹恼程序员的十件事(5)
- PHP邮件发送例子,已测试成功(5)
- 致初学者:PHP比ASP优秀的七个理由(4)
- PHP会被淘汰吗?(4)
- PHP新手上路(四)(4)
- 如何去学习PHP?(2)
- 简单入门级php分页代码(2)
- php中邮箱email 电话等格式的验证(2)