很久以前写的一个功能,当时需要一个优先级的队列,特用新学的swoole写了一个简单的demo,仅满足当时的需求。

功能说明:

    完全参考httpsqs增加优先级参数level

例:
            http://192.168.8.18:5555/?name=t ... a=testdata1&level=1
            http://192.168.8.18:5555/?name=t ... a=testdata2&level=1
            http://192.168.8.18:5555/?name=t ... a=testdata3&level=3
           此时,循环调用get方法,将获取数据testdata3,testdata1,testdata2
           注:get时先弹出优先级高的数据;同等优先级数据,按put的先后弹出;

用到的工具:

PHP PHP的swoole扩展

思路:

    使用swoole扩展监听端口,接收用户传入的参数;用全局变量$info存储所有队列名、每个队列的状态信息(所有优先级、每个优先级中已读数据个数,未读数据个数)等;设置定时器,定时将info写入文件;实际数据存入文件,每个数据占一行,使用fgets按行读出;全局变量$fp保存所有打开的文件句柄,减少文件的打开次数;

优势:
        使用世界上最好的语言PHP开发!

性能测试:
1:写性能:

ab -c 100 -n 10000 http://192.168.8.18:5555/?name=test\&opt=put\&data=testdata\&level=3

  

2:读性能

ab -c 100 -n 10000 http://192.168.8.18:5555/?name=test\&opt=get

附:基础代码

<?php
//带优化级的http队列服务
error_reporting(E_ERROR | E_WARNING | E_PARSE);
date_default_timezone_set('PRC');
$dirname = "./data/queue_"; //文件存储位置及文件名
$infodirname = "./data/info"; //存储基本信息的文件
$maxfilesize = 1024 * 1024 * 1024;//文件最大1G
$fp = array(); //打开文件的句柄
$info = array(); //存储各个队列的基本信息,get/put的位置
$infoflag = 0; //标记info是否被修改过
$tmp = file_get_contents($infodirname);//初始化,从文件中载入基本信息
!empty($tmp) && $info = unserialize($tmp); $http = new swoole_http_server("0.0.0.0", 5555);
$http->set(array(
'worker_num' => 1, //工作进程数量
));
$http->on('WorkerStart', function($http) {
$http->addtimer(10000);//增加定时器
});
$http->on('Timer', 'cronWriteInfo'); //定时将基本信息写入文件 $http->on('request', "mycallback");
$http->start(); function cronWriteInfo() { //定时写文件
global $info,$infoflag,$infodirname;
if($infoflag) { //info被修改过时,才将之写入文件
file_put_contents($infodirname, serialize($info));
}
}
function mycallback($request, $response) {
global $info, $infoflag;
if($request->server['request_uri'] == "/favicon.ico") { //过滤掉浏览器的icon请求
$response->end(" \n");
return '';
}
$infoflag = 1;
$param = $request->get;
if(empty($param['name'])) {//队列名字不能为空
$ret = "QUEUE_ERROR_QUEUENAME_EMPTY";
} else {
switch ($param['opt']) {
case 'get':
$ret = get($param['name']);
break;
case 'put':
if(($data = $param['data']) && !empty($param['data'])) {
empty($param['level']) && $param['level'] = 0;
$ret = put($param['name'], $param['data'], $param['level']);
} else {
$ret = "QUEUE_PUT_ERROR";
}
break;
case 'status':
$ret = json_encode($info);
break;
default:
$ret = "QUEUE_ERROR_PARAM";
break;
}
}
$response->end($ret."\n");
}
function get($queuename) {
global $info;
if($info[$queuename]['unread'] > 0) {
$maxlevel = $info[$queuename]['curMaxlevel']; //当前最大优化级
$pos = $info[$queuename]['leveldata'][$maxlevel]['getpos']; //文件偏移量
$data = getdataFromFile($queuename, $maxlevel, $pos); //读取数据
$ret = pack("H*", $data); //data是压缩的数据,需要解压
//修改全局变量
$info[$queuename]['get']++;
$info[$queuename]['unread']--;
$info[$queuename]['leveldata'][$maxlevel]['unread']--;
if($ret == "QUEUE_END") { //读到的数据不全,原因:数据文件大小超过最大值设置;
$data = getdataFromFile($queuename, $maxlevel, 0); //从头再读一次
$ret = pack("H*", $data); //data是压缩的数据,需要解压
$info[$queuename]['leveldata'][$maxlevel]['get'] = 1;//读取位置设为1
$info[$queuename]['leveldata'][$maxlevel]['getpos'] = strlen($data) + 1;
} else {
$info[$queuename]['leveldata'][$maxlevel]['get']++;
$info[$queuename]['leveldata'][$maxlevel]['getpos'] += strlen($data) + 1 ;
}
if($info[$queuename]['leveldata'][$maxlevel]['get'] == $info[$queuename]['leveldata'][$maxlevel]['put']) { //数据读取完毕,重新计算当前最高优先级的数据
$info[$queuename]['curMaxlevel'] = getcurMaxlevel($info[$queuename]['leveldata']);
}
return $ret;
} else {
return 'QUEUE_EMPTY';
}
}
function put($queuename, $userdata, $level) {
global $info;
if($info[$queuename]['leveldata'][$level]['put']+1 == $info[$queuename]['leveldata'][$level]['get']) { //队列写满
return "QUEUE_FULL";
}
$info[$queuename]['put']++;
$info[$queuename]['unread']++;
$newpos = setDataToFile($queuename, $level, $userdata);
$info[$queuename]['leveldata'][$level]['put']++;
$info[$queuename]['leveldata'][$level]['unread']++;
$info[$queuename]['leveldata'][$level]['putpos'] = $newpos;
$info[$queuename]['curMaxlevel'] = getcurMaxlevel($info[$queuename]['leveldata']);
return "QUEUE_PUT_OK";
} //获取当前需要执行的优先级最高的数据
function getcurMaxlevel($leveldata) {
krsort($leveldata);
foreach($leveldata as $level => $info) {
if($info['unread'] > 0) {
return $level;
}
}
return 0;
} //写数据到文件,如果文件写满,循环写入;
function setDataToFile($queuename, $level, $userdata) {
global $dirname, $maxfilesize, $fp;
$file = $dirname.$queuename.$level;
$packdata = unpack("H*", $userdata);
//$$packdata['1'] = $userdata;
$data = $packdata['1']."\n";
$size = filesize($file);
if(!$fp[$queuename][$level]) {
$fp = fopen($file, "ab+");
}
fseek($fp, $size);
fwrite($fp, $data);
clearstatcache();
if($size + strlen($data) + 1 > $maxfilesize) { //超出文件最大值,进入下一轮
fseek($fp, $size); //倒回指针
fwrite($fp, "QUEUE_END"); //写入标记符号
fseek($fp,0);//重头写
fwrite($fp, $data);
return strlen($data);
} else {
return $size + strlen($data);
}
}
//从文件中读取数据
function getdataFromFile($queuename, $level, $pos) {
global $dirname,$fp;
if(!isset($fp[$queuename][$level])) {
$file = $dirname.$queuename.$level;
$fp = fopen($file, "ab+");
}
fseek($fp, intval($pos));
return trim(fgets($fp));
}

带优先级的队列 - PHP实现的更多相关文章

  1. 可参数化的带优先级的数据选择器的FPGA实现方式探讨

    在FPGA设计中,大部分情况下我们都得使用到数据选择器.并且为了设计参数化,可调,通常情况下我们需要一个参数可调的数据选择器,比如M选1,M是可调的参数. 如果,数据选择器是不带优先级的,我们可以使用 ...

  2. FPGA中带优先级的if else if与不带优先级的case的探讨

    我们知道在书本上都说让我们尽量使用不带优先级的的数据选择器,今天我们就来探讨一下二者的区别. 例子1:带优先级的的数据选择器,综合成功,且没有任何警告. module detection_prio # ...

  3. Redis学习之实现优先级消息队列

    很久没有写博客了,最近简单的学习了一下Redis,其中学习了一下用Redis实现优先级消息队列.关于更多更为详细的可以在www.redis.cn找到相关资料. 对于熟悉Redis的童鞋提到队列很自然的 ...

  4. RabbitMQ学习笔记五:RabbitMQ之优先级消息队列

    RabbitMQ优先级队列注意点: 1.只有当消费者不足,不能及时进行消费的情况下,优先级队列才会生效 2.RabbitMQ3.5以后才支持优先级队列 代码在博客:RabbitMQ学习笔记三:Java ...

  5. redis+PHP实现的一个优先级去重队列

    主要思路是用一个set做前端去重缓冲, 若干个list做后端的多优先级消息队列, 用一个进程来进行分发, 即从set中分发消息到队列. set缓冲的设计为当天有效, 所以有个零点问题,有可能在零点前s ...

  6. 自定义ThreadPoolExecutor带Queue缓冲队列的线程池 + JMeter模拟并发下单请求

    .原文:https://blog.csdn.net/u011677147/article/details/80271174 拓展: https://github.com/jwpttcg66/GameT ...

  7. C++自带栈与队列_stack_queue_C++

    栈和队列我们可以用C++里自带的函数使用,就不必手写了 1.栈,需要开头文件 #include<stack>  定义一个栈s:stack<int> s; 具体操作: s.emp ...

  8. rabbitmq设置消息优先级、队列优先级配置

    1.首先在consume之前声明队列的时候,要加上x-max-priority属性,一般为0-255,大于255出错  -----配置队列优先级 配置成功后rabbitmq显示: 2.在向exchan ...

  9. poj 2828 buy Tickets 用线段树模拟带插入的队列

    Buy Tickets Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=2 ...

随机推荐

  1. Android 进阶Android 中的 IOC 框架 【ViewInject】 (上)

    1.概述 首先我们来吹吹牛,什么叫IoC,控制反转(Inversion of Control,英文缩写为IoC),什么意思呢? 就是你一个类里面需要用到很多个成员变量,传统的写法,你要用这些成员变量, ...

  2. 如何阅读《ECMAScript 2015 Language Specification》

    你不需要把<ECMAScript 2015 Language Specification>通读一遍,因为没那个必要.   阮一峰建议: 对于一般用户来说,除了第4章,其他章节都涉及某一方面 ...

  3. C++去掉字符串首尾的 空格 换行 回车

    /* *去掉字符串首尾的 \x20 \r \n 字符 */ void TrimSpace(char* str) { ; char *end = str; char *p = str; while(*p ...

  4. Beaglebone Black – 连接 GY-91 MPU9250+BMP280 九轴传感器(2)

    这次用 SPI.BBB 有两套 SPI 接口可用,两套都是默认 disable,需要用 overlay 方式启用,即: echo BB-SPIDEV0 > /sys/devices/bone_c ...

  5. mongodb中的副本集搭建实践

    准备运行1个主节点,2个从节点,从节点中其中是一个是仲裁节点(Arb). --oplogSize --oplogSize --oplogSize 其中application是副本集的名称,节点必须相同 ...

  6. QT mainwindow四件套

    最近在学习QT.下面总结一下mainwindow的设置步骤. 使用的平台为vs2013+qt5.3.2+qt-vs-addin1.2.3 1)安装软件 首先安装vs2013,这个不多介绍. 然后安装q ...

  7. 深入浅出设计模式——组合模式(Composite Pattern)

    模式动机 对于树形结构,当容器对象(如文件夹)的某一个方法被调用时,将遍历整个树形结构,寻找也包含这个方法的成员对象(可以是容器对象,也可以是叶子对象,如子文件夹和文件)并调用执行.(递归调用)由于容 ...

  8. js给文本框赋值 value与innerHTML

    <input type="test" name="testName" id="testId"> 赋值操作: <script ...

  9. 自定义datagridview列,却提示DataGridView 控件中至少有一列没有单元格模板

    哈哈,一个小误区,你看看设计窗体生成的代码,DataGridView的列不是GridViewColumn 而是DataGridViewTextBoxColumn你只要添加这个类型的对象就可以了,我也是 ...

  10. Android复习指南

    基础无外乎几部分:语言(C/C++或java),操作系统,TCP/IP,数据结构与算法,再加上你所熟悉的领域.这里面其实有很多东西,各大面试宝典都有列举. 在这只列举了Android客户端所需要的和我 ...