作为程序员一定要保持良好的睡眠,才能好编程

php-redis bitmap 用户签到模块设计

发布时间:2019-04-01

在系统开发时候,常常会使用到签到相关的模块,那么今天我们就来看看签到模块是怎么实现的:


首先来说,一个用户一年的签到情况,因为数据量比较小,都很容易的就会实现。


实现的方式有很多种,比如说

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