redis实现用户签到,统计活跃用户,用户在线状态,用户留存率
开发的过程中,可能会遇到用户签到、统计当天的活跃用户、以及每个用户的在线状态,用户留存率的开发需求,可能会用传统的方法,根据相应的需求设计数据库表等,但这样耗费的存储空间大,以及性能方面也不会太好,下面为大家介绍一些使用的方法
redis官方文档:http://www.redis.cn/documentation.html
一.用redis的set集合统计日活用户数
用户登录以后,把用户id添加到redis的set中,set会自动进行去重
127.0.0.1:6379> sadd users_2023_02_21 user1
(integer) 1
127.0.0.1:6379> sadd users_2023_02_21 user2
(integer) 1
127.0.0.1:6379> sadd users_2023_02_21 user3
(integer) 1
统计只需一条命令
127.0.0.1:6379> scard users_2023_02_21
(integer) 3
可以看出来,2023_02_21的用户数是3个,很简单,但是集合只适用于用户数比较少的场合,假如用户有100万,set存储100万个id号,如果一个id号占32个字节,总共就是差不多32M,一个月就是960M 差不多一个G了,用户量大的项目不适用
二.用redis中bitmap统计用户签到,活跃用户,用户在线状态,用户留存率等
思路:
1.设置一个key专门用来记录用户日活的,可以使用时间来翻滚
2.使用每个用户的唯一标识映射一个偏移量,比如使用id,这里可以把id换算成一个数字或直接使用id的二进制值作为该用户在当天是否活跃偏移量
3.用户登录则把该用户偏移量上的位值设置为1
4.每天按日期生成一个位图(bitmap)
5.计算日活则使用bitcount即可获得一个key的位值为1的量
6.计算月活(一个月内登陆的用户去重总数)即可把30天的所有bitmap做or计算,然后再计算bitcount
7.计算留存率(次日留存=昨天今天连续登录的人数/昨天登录的人数) 即昨天的bitmap与今天的bitmap做and计算就是连续登录的再做bitcount就得到连续登录人数,再bitcount得到昨天登录人数,就可以通过公式计算出次日留存
1.bitmap介绍
(1).BitMap是什么
就是通过一个bit位来表示某个元素对应的值或者状态,其中的key就是对应元素本身,我们知道8个bit可以组成一个Byte,所以bitmap本身会极大的节省储存空间,但其位计算和位表示数值相对于局限,故如要用位来做业务数据记录,那么就不要在意value的值了
(2).Redis中的BitMap
Redis从2.2.0版本开始新增了setbit,getbit,bitcount等几个bitmap相关命令,虽然是新命令,但是并没有新增新的数据类型,因为setbit等命令只不过是在set上的扩展
(3).几个前提:
数据在redis中都是二进制存储
setbit和getbit和bitcount是string数据类型的命令
8bit表示一个ascll字符,因为是c写的redis
offset偏移量是从0开始
(4)空间占用、以及第一次分配空间需要的时间
在一台2010MacBook Pro上,offset为2^32-1(分配512MB)需要大约300ms,offset为2^30-1(分配128MB)需要大约80ms,offset为2^28-1(分配32MB)需要大约30ms,offset为2^26-1(分配8MB)大约需要8ms<来自官方文档>
大概的空间占用计算公式是:($offset/8/1024/1024)MB
(5)getbit命令
指令 GETBIT key offset
返回值:字符串值指定偏移量上的位(bit)。当偏移量 OFFSET 比字符串值的长度大,或者 key 不存在时,返回 0 。
对 key 所储存的字符串值,获取指定偏移量上的位(bit)
注:offset表示偏移量
127.0.0.1:6379> set A a
OK
127.0.0.1:6379> get A
"a"
127.0.0.1:6379> getbit A 0
(integer) 0
127.0.0.1:6379> getbit A 1
(integer) 1
127.0.0.1:6379> getbit A 2
(integer) 1
127.0.0.1:6379> getbit A 3
(integer) 0
127.0.0.1:6379> getbit A 4
(integer) 0
127.0.0.1:6379> getbit A 5
(integer) 0
127.0.0.1:6379> getbit A 6
(integer) 0
(5)setbit命令
指令 SETBIT key offset value
返回值:指定偏移量原来储存的位
设置或者清除key的value(字符串)在offset处的bit值(只能只0或者1)
将上述A的值“a”的第6位修改为1,也就是相当于ASCLL码加2,从而值从a变成了c
127.0.0.1:6379> setbit A 6 1
(integer) 0
127.0.0.1:6379> get A
"c"
127.0.0.1:6379>
(6).Bitcount 命令
指令BITCOUNT key [start] [end]
返回值:1比特位的数量
计算给定key的字符串值中,被设置为 1 的比特位的数量
不存在的 key 被当成是空字符串来处理,因此对一个不存在的 key 进行 BITCOUNT 操作,结果为 0
值c的二进制数应该是01100011,故bitcount计算出来应该是4
127.0.0.1:6379> get A
"c"
127.0.0.1:6379> bitcount A
(integer) 4
(7).bitop 命令
指令 operation 可以是 AND 、 OR 、 NOT 、 XOR 这四种操作中的任意一种:
BITOP AND destkey key [key ...] ,对一个或多个 key 求逻辑并,并将结果保存到 destkey
BITOP OR destkey key [key ...] ,对一个或多个 key 求逻辑或,并将结果保存到 - destkey
BITOP XOR destkey key [key ...] ,对一个或多个 key 求逻辑异或,并将结果保存到 destkey
BITOP NOT destkey key ,对给定 key 求逻辑非,并将结果保存到 destkey
除了 NOT 操作之外,其他操作都可以接受一个或多个 key 作为输入
对一个或多个保存二进制位的字符串 key 进行位元操作,并将结果保存到 destkey 上
BITOP 的复杂度为 O(N) ,当处理大型矩阵(matrix)或者进行大数据量的统计时,最好将任务指派到附属节点(slave)进行,避免阻塞主节点
2.使用场景一:用户签到
需要展示最近一个月的签到情况,使用bitmap
<?php
$redis = new Redis();
$redis->connect('127.0.0.1');
//用户uid
$uid = 1;
//记录有uid的key
$cacheKey = sprintf("sign_%d", $uid);
//开始有签到功能的日期
$startDate = '2023-02-21';
//今天的日期
$todayDate = '2023-02-21';
//计算offset
$startTime = strtotime($startDate);
$todayTime = strtotime($todayDate);
$offset = floor(($todayTime - $startTime) / 86400);
echo "今天是第{$offset}天" . PHP_EOL;
//签到
//一年一个用户会占用多少空间呢?大约365/8=45.625个字节,好小
$redis->setBit($cacheKey, $offset, 1);
//查询签到情况
$bitStatus = $redis->getBit($cacheKey, $offset);
echo 1 == $bitStatus ? '今天已经签到啦' : '还没有签到呢';
echo PHP_EOL;
//计算总签到次数
echo $redis->bitCount($cacheKey) . PHP_EOL;
3.使用场景二:统计活跃用户
使用时间作为cacheKey,然后用户ID为offset,如果当日活跃过就设置为1
那么该如果计算某几天/月/年的活跃用户呢(暂且约定,统计时间内只有有一天在线就称为活跃)
命令 BITOP operation destkey key [key ...]
说明:对一个或多个保存二进制位的字符串 key 进行位元操作,并将结果保存到 destkey 上
说明:BITOP 命令支持 AND 、 OR 、 NOT 、 XOR 这四种操作中的任意一种参数
$redis = Yii::$app->redis_sms;
//日期对应的活跃用户
$data = array(
'2023-02-21' => array(10000030, 10600031, 10050031, 10040031, 10200031, 10020031, 10001001, 10000011, 10000021, 10000131),
'2023-02-20' => array(10000030, 10600031, 10050031, 10040031, 10200031, 10020031, 10110001, 10000011),
'2023-02-19' => array(10000030, 10600031, 10050031, 10040031, 10200031),
'2023-02-18' => array(10000030, 10600031),
'2023-02-17' => array(10000030, 10600031, 10050031,)
);//批量设置活跃状态
foreach ($data as $date => $uids) {$y = date("Y", strtotime($date));$m = date("m", strtotime($date));$d = date("d", strtotime($date));$cacheKey = sprintf("active_user:%s:%s:%s", $y, $m, $d);foreach ($uids as $uid) {$redis->setbit($cacheKey, $uid - 10000000, 1); // 偏移量,用户初始id较大时使用,减少redis计算}
}$redis->bitop('AND', 'active_user:stat', 'active_user:2023:02:21', 'active_user:2023:02:200') . PHP_EOL;
//总活跃用户:6
echo "总活跃用户:" . $redis->bitcount('active_user:stat') . PHP_EOL;
$redis->bitop('AND', 'active_user:stat1', 'active_user:2023:02:19', 'active_user:2023:02:18', 'active_user:2023:02:12') . PHP_EOL;
//总活跃用户:2
echo "总活跃用户:" . $redis->bitcount('active_user:stat1') . PHP_EOL;
$redis->bitop('AND', 'active_user:stat2', 'active_user:2023:02:18', 'active_user:2023:02:12') . PHP_EOL;
//总活跃用户:8
echo "总活跃用户:" . $redis->bitcount('active_user:stat2') . PHP_EOL;// 获取活跃状态的用户id
$result = $this->get_bitmap_all("active_user:2023:02:19");public function get_bitmap_all($key){$redis = Yii::$app->redis;$result = [];$value = $redis->get($key);if ($value) {/*** 解包(redis返回来的是二进制字符串,我们需要把它解成对应的数字)* 关于unpack的用法,如果不了解,大家可以网上搜索学习,改天可以单独写篇文章分享*/$bitmap = unpack('C*', $value);if ($bitmap) {foreach ($bitmap as $key => $number) {// 下标是从1开始的; 1个字节8位$offset = ($key - 1) * 8;// 过滤没有标记的字节段if ($number) {for ($i = 0; $i < 8; $i++) {// 遍历这个字节的每一位,是否有为1的值,如果有,那就记录这个位置的偏移量,就是用户idif (($number >> $i & 1) == 1) {// 8位范围是0~7,因为redis是高位到低位存储,所以要反过来计算偏移量$result[] = $offset + (7 - $i);}}}}}}return $result;}
/*** 新增上一天的日活跃用户数,以及更新上一天所在的月份的月活跃用户数*/public function actionActiveUser(){$day = 1;$date_key = date("Y:m:d", strtotime("-{$day} day"));$date = date("Y-m-d", strtotime("-{$day} day"));$redisUser = Yii::$app->redis_user;$platforms = array_keys(Common::fromPlatformText());//获取平台//保存对应日期平台活跃的用户到数据库foreach ($platforms as $platform) { //循环平台$key = sprintf("active_user:%s:%s", $date_key, $platform);//1.查询redis活跃用户id//2.查询到的用户id组成一个数组(该数组可能会很大)$userIds = $this->get_bitmap_all($key);if ($userIds) {//3.循环查询(使用yield生成器)用户注册表(t_reg)获取代理渠道相关信息$i_userIds = $this->activeUser($userIds);foreach ($i_userIds as $userId) {$key = sprintf("active_user:%s:%s", $date_key, $platform);//从用户注册表(reg)中获取对应用户渠道相关数据$reg = Reg::getGameUserData(['id' => $userId], ['agency_from', 'time']);if (!$reg) {continue;}$agencyFromPId = $reg['id']; //渠道id,默认为0:0 无渠道//4.重组key, 增加渠道id,把数据保存到redis服务器中$key .= ":" . $agencyFromPId;$redisUser->setbit($key, $userId, 1);$redisUser->expire($key, 15552000);//半年过期时间}}}//5.添加数据到活跃用户数据表进行统计//获取代理渠道类型以及对应的代理渠道商$agency_from = Common::agencyFrom();//保存当前日期平台对应的所有渠道对应的活跃用户到数据库foreach ($platforms as $platform) { //循环平台foreach ($agency_from as $id) { //循环渠道相关信息//构建活跃用户key$key = sprintf("active_user:%s:%s:%s", $date_key, $platform, $id);if ($redisUser->exists($key)) { // 判断key是否存在$num = $redisUser->bitcount($key);//获取当前日期对应平台对应的渠道的活跃用户//5.添加用户活跃数据ActiveUser::addInfo(['date' => $date, 'platform' => $platform, 'num' => $num, 'agency_from_id' => $id]);}}}//保存当前日期所在月份平台对应的所有渠道的活跃用户到数据库//生成月份数据$month = date("Y-m", strtotime($date));$timestamp = strtotime($month);$month_format = date("Y:m", $timestamp); // 月份时间格式$m_days = date('t', $timestamp); //当前月份的天数$date_start = strtotime(date('Y-m-01', $timestamp)); //当前月份开始日期戳$date_end = strtotime(date('Y-m-' . $m_days, $timestamp));//当前月份结束日期戳for ($i = $date_end; $i >= $date_start; $i -= 86400) { // 循环当前月份所在日期$dateKey = date("Y:m:d", $i);foreach ($platforms as $platform) { //循环平台,添加并更新当前月份活跃用户数据总数到redis服务器中foreach ($agency_from as $id) { //循环渠道相关信息$monthKey = 'active_user_month_num:' . $month_format . ":" . $platform . ":" . $id; // 月份活跃用户数量key$key = sprintf("active_user:%s:%s:%s", $dateKey, $platform, $id ); //获取活跃用户keyif ($redisUser->exists($key)) {//添加并更新当前月份活跃用户数据总数到后台redis服务器中$redisUser->bitop('or', $monthKey, $monthKey, $key); //bitop活跃用户$redisUser->expire($monthKey, 15552000);//半年过期时间 }}}}//保存当前月份平台对应的所有代理渠道商对应的活跃用户到数据库foreach ($platforms as $platform) { //循环渠道,bitOp活跃用户foreach ($agency_platform as $id) {$monthKey = 'active_user_month_num:' . $month_format . ":" . $platform . ":" . $id; // 月份活跃用户数量keyif ($redisUser->exists($monthKey)) {$num = $redisUser->bitcount($monthKey); //bitop活跃用户//保存前日期所在月份的渠道活跃的用户到数据库ActiveUser::addOrUpdate(['date' => $month, 'platform' => $platform, 'num' => $num, 'agency_from_id' => $id]);}}}}/*** yield生成器* @param $userIds* @return \Generator*/public function activeUser($userIds) {//使用yield生成器foreach ($userIds as $userId) {yield $userId;}}
4.使用场景三:实现用户上线次数统计
需求:
假设希望记录开发网站上的用户上线的频率,比如:计算用户 A 上线了多少天,用户 B 上线了多少天,从而决定让哪些用户参加 某个活动,这个功能可以使用 SETBIT 和 BITCOUNT 来实现。
每当用户在某一天上线的时候,我们就使用 SETBIT ,以用户id作为 key ,将那天所代表的网站的上线日作为 offset 参数,并将这个 offset 上的为设置为 1
案例:
如果今天是网站上线的第365天,而用户10001在今天浏览过网站,那么执行命令 SETBIT 10001 365 1 ;如果明天用户10001 也继续浏览网站,那么执行命令 SETBIT 10001 366 1 ,以此类推。当要计算用户10001 总共以来的上线次数时,就使用 BITCOUNT 命令:执行 BITCOUNT 10001 ,得出的结果就是 用户10001上线的总天数
5.使用场景四:用户在线状态
思路:
查询当前用户是否在线,使用bitmap是一个节约空间效率又高的一种方法,设置一个key,用户ID为offset,如果在线就设置为1,不在线就设置为0
$redis = Yii::$app->redis;//时段对应的在线用户$data = array('2023-02-14 05:00:00' => array(10000030, 10600031),'2023-02-15 05:00:00' => array(10000030, 10600031),'2023-02-15 13:00:00' => array(10000030, 10600031, 10050031, 10050031, 10040031, 10200031, 10020031, 10110001),'2023-02-19 12:00:00' => array(10000030, 10600031, 10050031, 10040031, 10200031, 10020031, 10001001, 10000011, 10000021, 10000131),'2023-02-18 13:00:00' => array(10000030, 10600031, 10050031, 10050031, 10040031, 10200031, 10020031, 10110001),'2023-02-16 13:00:00' => array(10000030, 10600031, 10050031, 10040031, 10200031),);//批量设置在线用户状态foreach ($data as $date => $uids) {$y = date("Y", strtotime($date));$m = date("m", strtotime($date));$d = date("d", strtotime($date));$H = date("H", strtotime($date));$cacheKey = sprintf("online_user:%s:%s:%s:%s", $y, $m, $d, $H);foreach ($uids as $uid) {$redis->setbit($cacheKey, $uid - 10000000, 1);}}$redis->bitop('AND', 'online_user:stat', 'online_user:2023:02:17:13', 'online_user:2023:02:18:13') . PHP_EOL;//总在线用户:6echo "总在线用户:" . $redis->bitcount('online_user:stat') . PHP_EOL;$redis->bitop('AND', 'online_user:stat1', 'online_user:2023:02:18:13', 'online_user:2023:02:15:11') . PHP_EOL;//总在线用户:2echo "总在线用户:" . $redis->bitcount('online_user:stat1') . PHP_EOL;
6.使用场景五:计算用户留存率
/*** 计算用户留存率并保存到mysql:30天用户留存率* @return string*/public function actionRetentionRateUser(){$date_start = date('Y-m-d', strtotime('-1 month'));$date_end = date('Y-m-d');$date_start = strtotime($date_start);$date_end = strtotime($date_end);$redis = Yii::$app->redis_user;$platforms = array_keys(Common::fromPlatformText()); //平台//循环日期,获取日期范围对应的用户留存率并保存到数据库for ($i = $date_end; $i >= $date_start; $i -= 86400) {//当前日期$date = date("Y:m:d", $i);//次日$date2 = date("Y:m:d", strtotime("+1 day", $i));//三日$date3 = date("Y:m:d", strtotime("+3 day", $i));//四日$date4 = date("Y:m:d", strtotime("+4 day", $i));//五日$date5 = date("Y:m:d", strtotime("+5 day", $i));//六日$date6 = date("Y:m:d", strtotime("+6 day", $i));//七日$date7 = date("Y:m:d", strtotime("+7 day", $i));//十五日$date15 = date("Y:m:d", strtotime("+15 day", $i));//三十日$date30 = date("Y:m:d", strtotime("+30 day", $i));//平台foreach ($platforms as $platform) {$key1 = 'active_user:' . $date . ':' . $platform;$key2 = $platform;$dest_day2 = 'retention_rate_user:' . $date . ':2day:' . $key2;$dest_day3 = 'retention_rate_user:' . $date . ':3day:' . $key2;$dest_day4 = 'retention_rate_user:' . $date . ':4day:' . $key2;$dest_day5 = 'retention_rate_user:' . $date . ':5day:' . $key2;$dest_day6 = 'retention_rate_user:' . $date . ':6day:' . $key2;$dest_day7 = 'retention_rate_user:' . $date . ':7day:' . $key2;$dest_day15 = 'retention_rate_user:' . $date . ':15day:' . $key2;$dest_day30 = 'retention_rate_user:' . $date . ':30day:' . $key2;//获取当前日期,上一天连续登录的人数$redis->bitop('AND', $dest_day2, $key1, 'active_user:' . $date2 . ':' . $key2);//获取当前日期,第三天连续登录的人数$redis->bitop('AND', $dest_day3, $key1, 'active_user:' . $date3 . ':' . $key2);//获取当前日期,第四天连续登录的人数$redis->bitop('AND', $dest_day4, $key1, 'active_user:' . $date4 . ':' . $key2);//获取当前日期,第五天连续登录的人数$redis->bitop('AND', $dest_day5, $key1, 'active_user:' . $date5 . ':' . $key2);//获取当前日期,第六天连续登录的人数$redis->bitop('AND', $dest_day6, $key1, 'active_user:' . $date6 . ':' . $key2);//获取当前日期,第七天连续登录的人数$redis->bitop('AND', $dest_day7, $key1, 'active_user:' . $date7 . ':' . $key2);//获取当前日期,第十五天连续登录的人数$redis->bitop('AND', $dest_day15, $key1, 'active_user:' . $date15 . ':' . $key2);//获取当前日期,第三十天连续登录的人数$redis->bitop('AND', $dest_day30, $key1, 'active_user:' . $date30 . ':' . $key2);//计算登录人数//当前日期登录人数$curCount = $redis->bitcount($key1);//当前日期,上一天连续登录的人数$nextCount = $redis->bitcount($dest_day2);//当前日期,第三天连续登录的人数$threeCount = $redis->bitcount($dest_day3);//当前日期,第四天连续登录的人数$fourCount = $redis->bitcount($dest_day4);//当前日期,第五天连续登录的人数$fiveCount = $redis->bitcount($dest_day5);//当前日期,第六天连续登录的人数$sixCount = $redis->bitcount($dest_day6);//当前日期,第七天连续登录的人数$sevenCount = $redis->bitcount($dest_day7);//当前日期,第十五天连续登录的人数$fifteenCount = $redis->bitcount($dest_day15);//当前日期,第三十天连续登录的人数$thirtyCount = $redis->bitcount($dest_day30);//设置半年过期时间$redis->expire($dest_day2, 15552000);$redis->expire($dest_day3, 15552000);$redis->expire($dest_day4, 15552000);$redis->expire($dest_day5, 15552000);$redis->expire($dest_day6, 15552000);$redis->expire($dest_day7, 15552000);$redis->expire($dest_day15, 15552000);$redis->expire($dest_day30, 15552000);//判断登录人数是否为0,为0的就不插入数据库了$count = $curCount + $nextCount + $threeCount + $fourCount + $fiveCount + $sixCount+ $sevenCount + $fifteenCount + $thirtyCount;if ($count == 0) {continue;}$params = ['cur_day' => $curCount,'next_day' => $nextCount,'three_day' => $threeCount,'four_day' => $fourCount,'five_day' => $fiveCount,'six_day' => $sixCount,'seven_day' => $sevenCount,'fifteen_day' => $fifteenCount,'thirty_day' => $thirtyCount,'date' => $date,'from_platform' => $platform,];//插入用户留存统计表RetentionRateUser::saveInfo($params); }}}
参考:https://blog.csdn.net/maoyuanming0806/article/details/81813776
参考:https://www.php.cn/php-weizijiaocheng-387074.html
相关文章:

redis实现用户签到,统计活跃用户,用户在线状态,用户留存率
开发的过程中,可能会遇到用户签到、统计当天的活跃用户、以及每个用户的在线状态,用户留存率的开发需求,可能会用传统的方法,根据相应的需求设计数据库表等,但这样耗费的存储空间大,以及性能方面也不会太好…...

MySQL中有多少种索引?索引的底层实现原理
索引存储在内存中,为服务器存储引擎为了快速找到记录的一种数据结构。索引的主要作用是加快数据查找速度,提高数据库的性能。索引的分类(1) 普通索引:最基本的索引,它没有任何限制。(2) 唯一索引:与普通索引类似&#…...

LeetCode经典算法题:二叉树遍历(递归遍历+迭代遍历+层序遍历)以及线索二叉树java详解
LeetCode经典算法题:二叉树遍历(递归遍历迭代遍历层序遍历)以及线索二叉树java详解 文章目录二叉树遍历题目描述解题思路与代码递归遍历迭代遍历层序遍历线索二叉树:二叉树遍历 题目描述 从根节点往下查找,先找左子树…...

【Java闭关修炼】MyBatis-接口代理的方式实现Dao层
【Java闭关修炼】MyBatis-接口代理的方式实现Dao层实现规则代码实现代理对象分析接口代理方式小结实现规则 映射配置文件中的名称空间必须和Dao层接口的全类名相同映射配置文件的增删改查标签的id属性必须和Dao层接口方法的参数相同映射配置文件中的增删改查标签的parameterTyp…...

2022年网络安全政策态势分析与2023年立法趋势
近日,公安部第三研究所网络安全法律研究中心与 360 集团法务中心联合共同发布了《全球网络安全政策法律发展年度报告(2022)》。《报告》概览2022年全球网络安全形势与政策法律态势,并对2023年及后续短期内网络安全政策、立法趋势进…...

使用vmware制作云平台redhat7.9镜像模板
一、概述 1.1 redhat7.9 定制镜像上传到云平台。 这个制作镜像得方式适用于多种iso 镜像。 将iso 镜像通过vmware 创建出一台虚机,对虚机做一些基础配置。在虚机上安装kvm 虚拟化得工具, 将iso 镜像在导入虚机种通过kvm创建一下虚机, 虚机创…...

OpenCV基础(28)使用OpenCV进行摄像机标定Python和C++
摄像头是机器人、监控、太空探索、社交媒体、工业自动化甚至娱乐业等多个领域不可或缺的一部分。 对于许多应用,必须了解相机的参数才能有效地将其用作视觉传感器。 在这篇文章中,您将了解相机校准所涉及的步骤及其意义。 我们还共享 C 和 Python 代码以…...

APB总线详解及手撕代码
本文的参考资料为官方文档AMBA™3 APB Protocol specification文档下载地址: https://pan.baidu.com/s/1Vsj4RdyCLan6jE-quAsEuw?pwdw5bi 提取码:w5bi APB端口介绍介绍总线具体握手规则之前,需要先熟悉一下APB总线端口,APB的端口…...

【Linux/Windows】源文件乱码问题解决方法总结
🐚作者简介:花神庙码农(专注于Linux、WLAN、TCP/IP、Python等技术方向)🐳博客主页:花神庙码农 ,地址:https://blog.csdn.net/qxhgd🌐系列专栏:Linux技术&…...

Python 四大主流 Web 编程框架
目前Python的网络编程框架已经多达几十个,逐个学习它们显然不现实。但这些框架在系统架构和运行环境中有很多共通之处,本文带领读者学习基于Python网络框架开发的常用知识,及目前的4种主流Python网络框架:Django、Tornado、Flask、Twisted。 …...

学UI设计,可以向哪些方向发展?该怎么学?
1、什么是UI设计?UI设计,全称 User Interface,翻译成中文意思叫做用户界面设计。2、UI设计的类型UI设计按用户和界面来分可分成四种UI设计。分别是移动端UI设计,PC端UI设计,游戏UI设计,以及其它UI设计。第一…...

【C++】初识CC++内存管理
前言 我们都知道C&C是非常注重性能的语言,因此对于C&C的内存管理是每一个C/C学习者必须重点掌握的内容,本章我们并不是深入讲解C&C内存管理,而是介绍C&C内存管理的基础知识,为我们以后深入理解C&C内存管理做铺…...

Nacos快速使用指南
简单例子:springboot快速集成nacos官方github文档命名空间是绝对隔离的。group之间可以通过配置实现跨 group访问配置中心Nacos config官方文档应用级别的默认配置文件名(dataId)dataId 的完整格式如下:${prefix}-${spring.profil…...

复旦发布国内首个类ChatGPT模型MOSS,和《流浪地球》有关?
昨晚,复旦大学自然语言处理实验室邱锡鹏教授团队发布国内首个类ChatGPT模型MOSS,现已发布至公开平台https://moss.fastnlp.top/ ,邀公众参与内测。 MOSS和ChatGPT一样,开发的过程也包括自然语言模型的基座训练、理解人类意图的对…...

国家级高新区企业主要经济指标(2012-2021年)
数据来源:国家统计局 时间跨度:2012-2021 区域范围:全国(及各分类统计指标) 指标说明:手工提取最新的中国统计年鉴数据中各个excel指标表,形成各个指标文件的多年度数据,便于多年…...

SpringBoot2核心技术-核心功能【05、Web开发】
目录 1、SpringMVC自动配置概览 2、简单功能分析 2.1、静态资源访问 1、静态资源目录 2、静态资源访问前缀 2.2、欢迎页支持 2.3、自定义 Favicon 2.4、静态资源配置原理 3、请求参数处理 0、请求映射 1、rest使用与原理 2、请求映射原理 1、普通参数与基本注解 …...

2021-03 青少年软件编程(C语言)等级考试试卷(六级)解析
2021-03 青少年软件编程(C语言)等级考试试卷(六级)解析T1. 生日相同 2.0 在一个有180人的大班级中,存在两个人生日相同的概率非常大,现给出每个学生的名字,出生月日。试找出所有生日相同的学生。 时间限制:1000 内存限制:65536 输入 第一行为整数n,表示有n个学生,n …...

数据库的多租户隔离
数据库的多租户隔离有三种方案 1、独立数据库 一个租户一个数据库,这种方案的用户数据隔离级别最高,安全性最好,成本也最高 优点:为不同的租户提供独立的数据库,有助于简化数据模型的扩展设计,满足不同租…...

网络输入分辨率是否越大越好
目标检测比如 yolov5,训练输入图像大小默认是 640*640,这个是不是越大训练的效果越好 ? 这个肯定不是的。而且,如果仅调整输入图像的分辨率,不改变网络结构的话,检测准确率反而会下降的。首先,…...

离线采集普遍解决方案
简介 使用Datax每日全量相关全量表,使用Maxwell增量采集到Kafka然后到Flume然后到Hdfs。 DataX全量 生成模板Json gen_import_config.py # codingutf-8 import json import getopt import os import sys import MySQLdb#MySQL相关配置,需根据实际情…...

SAP ABAP 数据类型P类型详解
ABAP中比较难以理解的是P类型的使用,P类型是一种压缩类型,主要用于存储小数,定义时要指定字节数和小数点位数,定义语法如下: DATA: name(n) TYPE P decimals m,n代表字节数,最大为16,m是小…...

应用沙盒seccomp的使用
应用沙盒原理参考https://zhuanlan.zhihu.com/p/513688516 1、什么是Seccomp? seccomp 是 secure computing 的缩写,其是 Linux kernel 从2.6.23版本引入的一种简洁的 sandboxing 机制。 系统调用: 在Linux中,将程序的运行空间分为内核与用户空间(内核态和用户态),在逻辑…...

C++项目——高并发内存池(2)——thread_cache的基础功能实现
1.并发内存池concurrent memory pool 组成部分 thread cache、central cache、page cache thread cache:线程缓存是每个线程独有的,用于小于64k的内存的分配,线程从这里申请内存不需要加锁,每个线程独享一个cache,这…...

【C进阶】数据的存储
文章目录:star:1. 数据类型:star:2. 整形在内存中的存储2.1 存储规则2.2 存储模式2.3 验证大小端模式:star:3. 数据范围3.1 整形溢出3.2 数据范围的求解3.3 练习:star:4. 浮点型在内存中的存储4.1 浮点数的存储规则4.2 练习5. :star::star:总结(思维导图)⭐️1. 数据类型 在了…...

【已解决】异常断电文件损坏clickhouse启动不了:filesystem error Structure needs cleaning
问题 办公室有一台二手服务器,作为平时开发测试使用。由于机器没放在机房,会偶发断电异常断电后,文件系统是有出问题的可能的,尤其是一些不断在读写合并的文件春节后,发现clickhouse启动不了,使用systemct…...

FlinkSQL行级权限解决方案及源码
FlinkSQL的行级权限解决方案及源码,支持面向用户级别的行级数据访问控制,即特定用户只能访问授权过的行,隐藏未授权的行数据。此方案是实时领域Flink的解决方案,类似离线数仓Hive中Ranger Row-level Filter方案。 源码地址: https…...

【基础篇】8 # 递归:如何避免出现堆栈溢出呢?
说明 【数据结构与算法之美】专栏学习笔记 什么是递归? 递归是一种应用非常广泛的算法(或者编程技巧),比如 DFS 深度优先搜索、前中后序二叉树遍历等等都是用到了递归。 方法或函数调用自身的方式称为递归调用,调用…...

基于微信公众号(服务号)实现扫码自动登录系统功能
微信提供了两种方法都可以实现扫描登录。 一种是基于微信公众平台的扫码登录,另一种是基于微信开放平台的扫码登录。 两者的区别: 微信开放平台需要企业认证才能注册(认证费用300元,只需要认证1次,后续不再需要进行缴费年审&#…...

AXI实战(二)-跟着产品手册设计AXI-Lite外设(AXI-Lite转串口实现)
AXI实战(二)-跟着产品手册设计AXI-Lite 设(AXI-Lite转串口实现) 看完在本文后,你将可能拥有: 一个AXI_Lite转串口的从端(Slave)设计使用SV仿真AXI-Lite总线的完整体验实现如何在读通道中实现"等待"小何的AXI实战系列开更了,以下是初定的大纲安排: 欢迎感兴趣的…...

一周搞定模拟电路视频教程,拒绝讲PPT,仿真软件配合教学,真正一周搞定
目录1、灵魂拷问2、懦夫救星3、福利领取2、使用流程1、灵魂拷问 问:模拟电路很难吗? 答:嗯,真的很难!!! 问:模拟电路容易学吗? 答:很难学,建议放…...