在系统开发时候,常常会使用到签到相关的模块,那么今天我们就来看看签到模块是怎么实现的:
首先来说,一个用户一年的签到情况,因为数据量比较小,都很容易的就会实现。
实现的方式有很多种,比如说
1、保存在数据库中
2、使用redis 保存在redis中。
这么多的存储都可以实现,为什么使用redis的bitmap 来实现呢? set 不也可以实现吗?
因为我们看中了 bitmap 存储空间占用大小的优势、 365/8/1024/1024 这是 一个用户1年签到占用空间的大小。 这也是这个数据结构的优势。
set 也是可以实现的,这个用户签到都保存在集合中,每次使用 sismember 判断是否存在于集合中。 占用空间相对于bitmap来说是 比较多的。
今天我们就使用redis来实现这种模式:
1、一个用户在365天中 签到的天数
模拟数据填充
$redis=new redis();
if(!$redis){
exit("redis init error");
}
$flag=$redis->connect("127.0.0.1",6379);
if(!$flag){
exit('redis connect error ');
}
$user1='user1';
$count=0;
while($count<60){
$day=mt_rand(1,365);
if(!$redis->getbit($user1,$day)){
$redis->setbit($user1,$day,1);
$count++;
}
}
$redis->close();2、求出365天中 连续签到天数最长的一次
连续签到? 怎么判断? 就是签到连续2天以上的 视为连续签到。
核心思想:
1、定义一个prevData 保存上一次签到的情况
2、定义$data保存此次的结果
3、如果查找中的一次是false,那么 比对$data 的长度与 $prevData的长度,如果超过了$prevData那么就替换。
核心代码:
$redis=new redis();
if(!$redis){
exit("redis init error");
}
$flag=$redis->connect("127.0.0.1",6379);
if(!$flag){
exit('redis connect error ');
}
$user1='user1';
$count=0;
$prevdata=[];
$data=[];
for($i=1;$i<=365;$i++){
if($redis->getbit($user1,$i)){
$data[]=$i;
}else{
if(count($data)>count($prevdata)){
$prevdata=$data;
}
$data=[];
}
}
$redis->close();
$endtime=microtime(true);
$endmemory=memory_get_usage();
3、365天中共计有多少次签到
数据存储在bitmap中了,bitmap中有一个函数 bitcount() 通过此函数可以快速检索到签到的次数
4、求出签到连续签到的次数
function echo_memory_usage($mem_usage) {
// $mem_usage = memory_get_usage(true);
if ($mem_usage < 1024)
echo $mem_usage." bytes";
elseif ($mem_usage < 1048576)
echo round($mem_usage/1024,2)." kilobytes";
else
echo round($mem_usage/1048576,2)." megabytes";
echo "<br/>";
}
$startime=microtime(true);
$starmemory=memory_get_usage();
$redis=new redis();
if(!$redis){
exit("redis init error");
}
$flag=$redis->connect("127.0.0.1",6379);
if(!$flag){
exit('redis connect error ');
}
$user1='user1';
$count=0;
$data=[];
for($i=1;$i<=365;$i++){
if($redis->getbit($user1,$i)){
$data[]=$i;
}else{
if(count($data)>1){
$count++;
}
$data=[];
}
}
$redis->close();
$endtime=microtime(true);
$endmemory=memory_get_usage();
print_r($count);
echo "内存:".echo_memory_usage($endmemory-$starmemory)."\n";
echo "时间:".($endtime-$startime)."\n";这样可以打印出 $count
5、签到中有哪些是连续签到的?分别是哪几天?
php代码:
function echo_memory_usage($mem_usage) {
// $mem_usage = memory_get_usage(true);
if ($mem_usage < 1024)
echo $mem_usage." bytes";
elseif ($mem_usage < 1048576)
echo round($mem_usage/1024,2)." kilobytes";
else
echo round($mem_usage/1048576,2)." megabytes";
echo "<br/>";
}
$startime=microtime(true);
$starmemory=memory_get_usage();
$redis=new redis();
if(!$redis){
exit("redis init error");
}
$flag=$redis->connect("127.0.0.1",6379);
if(!$flag){
exit('redis connect error ');
}
$user1='user1';
$count=0;
$prevdata=[];
$data=[];
$lxdata=[];
for($i=1;$i<=365;$i++){
if($redis->getbit($user1,$i)){
$data[]=$i;
}else{
if(count($data)>count($prevdata)){
$prevdata=$data;
}
if(count($data)>1){
$lxdata[]=$data;
}
$data=[];
}
}
$redis->close();
$endtime=microtime(true);
$endmemory=memory_get_usage();
print_r($prevdata);
print_r($lxdata);
echo "内存:".echo_memory_usage($endmemory-$starmemory)."\n";
echo "时间:".($endtime-$startime)."\n";[root@localhost bigfile]# php readqd2.php Array ( [0] => 310 [1] => 311 [2] => 312 [3] => 313 [4] => 314 ) Array ( [0] => Array ( [0] => 35 [1] => 36 ) [1] => Array ( [0] => 44 [1] => 45 [2] => 46 ) [2] => Array ( [0] => 51 [1] => 52 ) [3] => Array ( [0] => 98 [1] => 99 ) [4] => Array ( [0] => 156 [1] => 157 ) [5] => Array ( [0] => 167 [1] => 168 [2] => 169 ) [6] => Array ( [0] => 210 [1] => 211 ) [7] => Array ( [0] => 240 [1] => 241 ) [8] => Array ( [0] => 310 [1] => 311 [2] => 312 [3] => 313 [4] => 314 ) [9] => Array ( [0] => 321 [1] => 322 ) [10] => Array ( [0] => 336 [1] => 337 ) [11] => Array ( [0] => 360 [1] => 361 ) ) 3.84 kilobytes<br/>内存: 时间:0.055135011672974