Redis如何实现排行榜?
今天给大家简单聊聊 Redis Sorted Set 数据类型底层的实现原理和游戏排行榜实战。特别简单,一点也不深入,也就 7 张图,粉丝可放心食用,哈哈哈哈哈~~~~。
1. 是什么
Sorted Sets 与 Sets 类似,是一种集合类型,集合中不会出现重复的数据(member)。区别在于 Sorted Sets 元素由两部分组成,分别是 member 和 score。
member 会关联一个 double 类型的分数(score),sorted sets 默认会根据这个 score 对 member 进行从小到大的排序,如果 member 关联的分数 score 相同,则按照字符串的字典顺序排序。
这是规则,得记下来。
2-24
常见的使用场景:
-
排行榜,比如维护大型在线游戏中根据分数排名的 Top 10 有序列表。
-
速率限流器,根据排序集合构建滑动窗口速率限制器。
-
延迟队列,score 存储过期时间,从小到大排序,最靠前的就是最先到期的数据。
2. 修炼心法
Sorted Sets 底层有两种方式来存储数据。
-
在 7.0 版本之前是 ziplist,之后被 listpack 代替,使用 listpack 存储的条件是集合元素个数小于等于
zset-max-listpack-entries
配置值(默认 128),且 member 占用字节大小小于zset-max-listpack-value
配置值(默认 64)时使用 listpack 存储,member 和 score 紧凑排列作为 listpack 的一个元素进行存储。 -
不满足上述条件,使用 skiplist + dict(散列表) 组合方式存储,数据会插入 skiplist 的同时也会向 dict(散列表)中插入数据 ,是一种用空间换时间的思路。散列表的 key 存放的是元素的 member,value 存储的是 member 关联的 score。
❝MySQL:“也就是说 listpack 适用于元素个数不多且元素内容不大的场景。”
对,使用 listpack 存储的目的就是节省内存。
Sorted Sets 能支持高效的范围查询,正是因为采用了 skiplist 跳表,比如 ZRANGE
命令时时间复杂度为 O(log(n)) + m
, n 是 member 个数,m 是返回结果数。需要注意的是,你应该避免命令会返回大量结果。
而使用 dict 的原因是实现 O(1) 时间复杂度查询单个元素。比如 ZSCORE key member
指令。
总结来说,Sorted Sets 在插入或者更新的时候,会同时往 skiplist 和 散列表中插入或者更新对应的数据。保证 skiplist 和散列表的数据一致。
❝MySQL:“这个方式很巧妙呀,skiplist 用来根据 score 进行范范围查询或者单个查询,dict 散列表则用于实现 O(1) 时间复杂度查根据数据查询对应 score,满足高效范围查询和单元素查询。“
sorted sets 实现源码主要在以下两个文件中。
-
结构定义在
server.h
。 -
功能实现在
t_zset.c
。
先看 skiplist(跳表) + dict(散列表)数据结构如何存储数据。
skiplist + dict
❝MySQL:“说说什么是跳表吧”
实质就是一种可以进行二分查找的有序链表。跳表在原有的有序链表上面增加了多级索引,通过索引来实现快速查找。
不仅能提高搜索性能,还可以提高插入和删除操作的性能。它在性能上和红黑树、AVL 树不相上下,但是跳表的原理和实现比红黑树简单。
回顾链表,它的痛点就是查询很慢,O(n) 时间复杂度,作为唯快不破的 Redis 是不能忍的。
图2-25
如果在有序链表的每相邻两个节点增加一个“跳跃”指向下下个节点的指针,那么查找的时间复杂度就可以降低为原来的一半,如下图所示。
图 2-26
这样 level 0 和 level 1 分别形成两个链表,level 1 层的链表节点个数只有 2 个(6、26)。
跳表节点查找
查找数据总是从最高层开始比较,如果节点保存的值比待查数据小,跳表就继续访问该层的下一个节点;
如果碰到比待查数据值大的节点时,那就跳到当前节点的下一层的链表继续查找。
比如现在想查找 17,查找的路径如下图红色指向的方向进行。
-
从 level 1 开始,17 与 6 比较,值大于节点,继续与下一个节点比较。
-
与 26 比较,17 < 26,回到原节点,跳到当前节点的 level 0 层链表,与下一个节点比较,找到目标 17。
skiplist 正是受这种多层链表的想法启发设计出来的。按照上面的生成链表方式,每次往上增加一层链表的节点个数是下面一层的一半,这样的查找过程就类似于一个二分查找,时间复杂度为 O(log n)。
但是,这种方式在插入数据的时候有很大的问题,每次新增一个节点,就会打乱相邻的两层链表节点个数 2:1 的关系,如果要维持这个关系,就需要对链表调整,事件复杂度是 O(n)。
为了避免这个问题,它不要求上下相邻的两层链表节点个数有严格的比例关系,而是为每个节点随机出一个层数,这样插入节点只需要修改前后指针。
如下图是一个有 4 层链表的 skiplist,假设我们要查找 26,下图给出了查找经历过的路径。
对经典跳表有个直观的映像后,来看看 Redis 中 skiplist 的实现细节,Sorted Sets 数据结构定义如下。
typedef struct zset {dict *dict;zskiplist *zsl;
} zset;
zset
结构体中有两个变量,分别是散列表 dict 和跳表 zskiplist。dict 在前文已经讲过, 重点看 zskiplist
。
typedef struct zskiplist {// 头、尾指针便于双向遍历struct zskiplistNode *header, *tail;// 当前跳表包含元素个数unsigned long length;// 表内节点的最大层级数int level;
} zskiplist;
-
zskiplistNode *header, *tail
,两个头、尾指针,用于实现双向遍历。 -
length
,链表包含的节点总数。需要注意的是,新创建的zskiplist
会生成一个空的头指针,它不包含在 length 计数中。 -
level
,表示skiplist
中,所有节点层数的最大值。
接着继续看 skiplist 中每个节点的定义 zskiplistNode
结构体。
typedef struct zskiplistNode {sds ele;double score;struct zskiplistNode *backward;struct zskiplistLevel {struct zskiplistNode *forward;unsigned long span;} level[];} zskiplistNode;
-
Sorted Set 既要保存元素,又要保存元素的权重。所以对应了 sds 类型的 ele 存储实际内容, double 类型 score 用于保存权重。
-
*backward
,后退指针,指向该节点的上一个节点,便于从尾节点实现倒序查找。注意,每个节点只有一个后向指针,只有 level 0 层链表是一个双向链表。 -
level[]
,是一个zskiplistLevel
结构体类型的柔性数组。跳表是一个多层的有序链表,每一层的节点也是由指针链接起来的,所以数组中每个元素代表着 skiplist 的一层。-
*forward
,该层的前进指针。 -
span
,跨度,用来记录节点在该层的*forward
指针到指针指向的下一个节点之间跨越了 level0 层的节点数。span 用于计算元素排名(rank),例如查找 ele = 肖菜鸡、score = 17 的排名,只需要把查找路径经过的节点的 span 相加即可,如下图的红色路径的 span 累加,rank = (2 + 2) - 1 = 3
(减 1 是因为 rank 从 0 开始)。如果要计算从大到小的排名,只需要用 skiplist 长度减去查找路径上的 span 累加值,即4 - (2 + 2) = 0
。
-
下图展示了 Redis 中一个 skiplsit 的可能结构。
listpack
❝MySQL:“根据
zset
结构体定义可知,分别使用了 dict、zskiplist 两种数据结构,listpack 影子都见不着呀。“
这个问题问得好,使用 listpack 存储的细节在源码文件t_zset.c
中的zaddGenericCommand
函数中体现,部分代码如下,内部会判断是否使用 listpack 来存储。·
void zaddGenericCommand(client *c, int flags) {// 省略部分代码// key 不存在则创建 sorted setzobj = lookupKeyWrite(c->db,key);if (checkType(c,zobj,OBJ_ZSET)) goto cleanup;if (zobj == NULL) {if (xx) goto reply_to_client;// 当 zset_max_listpack_entries == 0 或者// 元素字节大小大于 zset_max_listpack_value 配置// 则使用 skiplist + dict 存储,否则使用 listpack。if (server.zset_max_listpack_entries == 0 ||server.zset_max_listpack_value < sdslen(c->argv[scoreidx+1]->ptr)){zobj = createZsetObject();} else {zobj = createZsetListpackObject();}dbAdd(c->db,key,zobj);}// 省略部分代码
}
我们知道,listpack 是一块由多个数据项组成的连续内存。而 sorted set 每一项元素是由 member 和 score 两部分组成。
采用 listpack 存储插入一个(member、score)数据对的时候,每个 member/score 数据对紧凑排列存储。
listpack 最大的优势就是节省内存,查找元素的话只能按顺序查找,时间复杂度是 O(n)。正是如此,在少量数据的情况下,才能做到既能节省内存,又不会影响性能。每一步查找前进两个数据项,也就是跨越一个 member/score 数据对。
3. 出招实战:排行榜
很多地方都会用到排行榜功能,比如微博热榜、知乎热榜、电影排行榜、游戏战力排行等。
以游戏排行榜为例,我教你使用 Sorted Set 实现一个实时游戏高分排行榜。
玩家的得分越高,排行越靠前,如果分数相同则先达到该分数的玩家排在前面,游戏排行榜的提供的功能如下。
-
按照分数从大到小排名,查询前 N 位玩家信息。
-
新注册玩家,需要把新玩家信息添加到排行榜中。
-
能查看某个玩家的排名和分数。
Sorted Set 每个元素有两部分组成(member + score),可利用 score 进行排序,正好满足我们的场景。用 score 保存玩家的游戏得分,member 保存玩家 ID。
❝王架构:“分数相同,先达到该分数的排在前面,也就是说,游戏分数相同的情况下,时间戳越小,排名越靠前,咋实现?”
这个问题问得好,既然时间也会影响排名,那就把时间戳考虑到 score 中。
❝王架构:“有问题,分数越大,排名越靠前;而时间戳越小,排名越靠前。两个规则相反的,怎么结合在一起。”
好问题,这时候你可以指定一个非常大的时间作为基准时间,比如这个时间就是你当年信誓旦旦的对那个女孩说:“如果非要在我们的爱上加一个期限,我是希望……一万年”,也就是 2023 + 10000 年。
执行时间排序值 =(基准时间 - 玩家达到分数时间)/ 基准时间
公式计算,得到的结果值一定小于 1,正好可作为 score 小数部分。越早达到,这个值就越大,满足排序。
最后score = 玩家游戏分 + ((基准时间 - 玩家获得某分数时间) / 基准时间),就实现了分数相同,先达到该分数的排在前面的功能。
代码逻辑如下所示。
private double calcScore(int playerScore, long playerScoreTime) {return playerScore + (BASE_TIME - playerScoreTime) * 1.0 / BASE_TIME;
}
-
playerScore,玩家游戏分。
-
playerScoreTime,玩家获得分数的时间秒数。
-
BASE_TIME,基准时间的时间秒数。
想要获取真正玩家游戏分数的时候,取整数位即可。接下来我来演示一下如何使用 zset 的指令实现排行榜。
假设 BASE_TIME 为 12023 年 1 月 1 日 0 时 0 分 0 秒时间戳秒数 = 317242022400。
更新排行榜
使用指令 ZADD key score member [score member...]
用于新增或者更新玩家排行榜。如下指令表示新增了 4 个玩家信息到排行榜。leaderboard:339
作为 key,表示区服 339 战力排行榜,玩家 2 和玩家 3 的战力都是 500 分,玩家 3 比玩家 2 先到达 500 战力。
redis> ZADD leaderboard:339 2500.994707057989 player:1
(integer) 1
redis> ZADD leaderboard:339 500.99470705798905 player:2
(integer) 1
redis> ZADD leaderboard:339 500.9947097814618 player:3
(integer) 1
redis> ZADD leaderboard:339 987770.994707058 player:4
(integer) 1
假设某天玩家 4 的女朋友不在家,他就天天玩游戏,战力提升到 1987770。执行如下指令,player:4 的 score 机会更新为 1987770.994707055。
ZADD leaderboard:339 1987770.994707055 player:4
获取 Top 3 玩家排行信息
ZRANGE
命令可以按照排名、score、字典排序进行范围查询。语法使用规则
ZRANGE key start stop [BYSCORE | BYLEX] [REV] [LIMIT offset count] [WITHSCORES]
默认排序是按照 score 由低到高,分数相同则根据 member 字典排序。
-
REV,可选参数,按照 score 由高到低逆序排序。
-
LIMIT offset count 可选参数,类似于 MySQL 的使用,需要注意的是, count 为负数则返回所有符合数据。
-
WITHSCORES 可选参数,返回 score 和 member,返回的格式是 member 1,score 1,…memberN,scoreN。
你可以使用 REV
来实现逆序,WITHSCORES
返回 member 和 score。如下指令的一是是从 key 为 leaderboard:339 的 Sorted Set 中按照 score 逆序排序获取 3 个元素。
> ZRANGE leaderboard:339 0 2 REV WITHSCORES
player:4
1987770.9947070549
player:1
2500.9947070579892
player:3
500.99470978146178
获取指定玩家排名
我提供了 ZREVRANK
指令,用于返回指定 member 的排名,需要注意的是,排名从 0 开始。如下指令查找 player:4 的排名,0 表示第一。
> ZREVRANK leaderboard:339 player:4
0
相关文章:
![](https://img-blog.csdnimg.cn/img_convert/a361e811a880ba6f7625dc4b277dd9da.png)
Redis如何实现排行榜?
今天给大家简单聊聊 Redis Sorted Set 数据类型底层的实现原理和游戏排行榜实战。特别简单,一点也不深入,也就 7 张图,粉丝可放心食用,哈哈哈哈哈~~~~。 1. 是什么 Sorted Sets 与 Sets 类似,是一种集合类型ÿ…...
![](https://img-blog.csdnimg.cn/edb09b9f59a64164a363d84daaaeaf74.png)
Pycharm debug程序,跳转至指定循环条件/循环次数
在断点出右键,然后设置条件 示例 for i in range(1,100):a i 1b i 2print(a, b, i) 注意: 1、你应该debug断点在循环后的位置而不是循环上的位置,然后你就可以设置你的条件进入到指定的循环上了 2、设置条件,要使用等于符号…...
![](https://www.ngui.cc/images/no-images.jpg)
react实现markdown
参考:https://blog.csdn.net/Jack_lzx/article/details/118495763 参考:https://blog.csdn.net/m0_48474585/article/details/119742984 0. 示例 用react实现markdown编辑器 1.基本布局及样式 <><div classNametf_editor_header>头部&…...
![](https://img-blog.csdnimg.cn/img_convert/4752117caece78674b127ecb65328e46.png)
HTTP请求走私漏洞简单分析
文章目录 HTTP请求走私漏洞的产生HTTP请求走私漏洞的分类HTTP请求走私攻击的危害确认HTTP请求走私漏洞通过时间延迟技术确认CL漏洞通过时间延迟技术寻找TE.CL漏洞 使用差异响应内容确认漏洞通过差异响应确认CL.TE漏洞通过差异响应确认TE.CL漏洞 请求走私漏洞的利用通过请求漏洞…...
![](https://img-blog.csdnimg.cn/img_convert/fa06f9186c95dca037d2f7f17e8761b1.webp?x-oss-process=image/format,png)
BI-SQL丨两表差异比较
BOSS:哎,白茶,我们最近新上了一个系统,后续有一些数据要进行源切换,这个能整么? 白茶:没问题,可以整! BOSS:哦,对了,差点忘记告诉你了…...
![](https://www.ngui.cc/images/no-images.jpg)
ZooKeeper 选举的过半机制防止脑裂
结论: Zookeeper采用过半选举机制,防止了脑裂。 原因: 如果有5台节点,leader联系不上了,其他4个节点由于超过半数,所以又选出了一个leader,当失联的leader恢复网络时,发现集群中已…...
![](https://img-blog.csdnimg.cn/0ebc1aa477b94e338268b260ddb7ed21.png)
【图论】树上差分(边差分)
一.简介 其实点差分和边差分区别不大。 点差分中,d数组存储的是树上的节点 边差分中,d数组存储的是当前节点到父节点的那条边的差分值。 指定注意的是:边差分中因为根连的父节点是虚点,所以遍历结果时应当忽略! 二…...
![](https://img-blog.csdnimg.cn/5238b55c6d344464a3f0c9fa195bc3f4.png)
RT1052的定时器
文章目录 1 通用定时器1.1 定时器框图1.2 实现周期性中断 2 相关寄存器3 定时器配置3.1 时钟使能3.2 初始化GPT1定时器3.2.1 base3.2.2 initConfig3.2.2.1 clockSorce3.2.2.2 divider3.2.2.3 enablexxxxx 3.3 设置 GPT1 比较值3.3.1 base3.3.2 channel3.3.3 value 3.4 设置 GPT…...
![](https://img-blog.csdnimg.cn/d74e04607cc247f88fb24811be85512b.png)
opencv python 训练自己的分类器
源码下载 一、分类器制作 1.样本准备 收集好你所需的正样本,和负样本,分别保存在不同文件夹 在pycharm新建项目,项目结构如下:has_mask文件夹放置正样本,no_mask文件夹放置负样本 安装opencv,把opencv包…...
![](https://img-blog.csdnimg.cn/73205cdc3d824c32a0f85aed5e471382.png)
详解Mybatis之分页插件【PageHelper】
编译软件:IntelliJ IDEA 2019.2.4 x64 操作系统:win10 x64 位 家庭版 Maven版本:apache-maven-3.6.3 Mybatis版本:3.5.6 文章目录 一. 什么是分页?二. 为什么使用分页?三. 如何设计一个Page类(分…...
![](https://img-blog.csdnimg.cn/35714a317ad449e5be72f38ece1c81db.png)
【基于矢量射线的衍射积分 (VRBDI)】基于矢量射线的衍射积分 (VRBDI) 和仿真工具(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
![](https://www.ngui.cc/images/no-images.jpg)
基于jackson对bean的序列号和反序列化
通过观察控制台输出的SQL发现页面传递过来的员工id的值和数据库中的id值不一致,这是怎么回事呢? 分页查询时服务端响应给页面的数据中id的值为19位数字,类型为long 页面中js处理long型数字只能精确到前16位,所以最终通过ajax请求提交给服务…...
![](https://img-blog.csdnimg.cn/ff7fcc9174bc474586c9cfd714eb8a43.png#pic_center)
排队理论简介
排队理论简介 1. 理论背景2. 研究的数学方法3. 拒绝型排队系统与等候型排队系统4. 拒绝型排队系统 本文参考文献为Вентцель Е. С.的《Исследование операций》。 1. 理论背景 排队理论又称大众服务理论,顾名思义指的是在有限的服务条…...
![](https://www.ngui.cc/images/no-images.jpg)
极速查找(3)-算法分析
篇前小言 本篇文章是对查找(2)的续讲二叉排序树 二叉排序树(Binary Search Tree,BST),又称为二叉查找树,是一种特殊的二叉树。性质: 左子树的节点值小于根节点的值,右…...
![](https://www.ngui.cc/images/no-images.jpg)
http 常见的响应状态码 ?
100——客户必须继续发出请求101——客户要求服务器根据请求转换HTTP协议版本200——交易成功201——提示知道新文件的URL202——接受和处理、但处理未完成203——返回信息不确定或不完整204——请求收到,但返回信息为空205——服务器完成了请求,用户代理…...
![](https://img-blog.csdnimg.cn/b4e72750ca1f4324918cb06989c6ced2.png#pic_center)
机器学习笔记之优化算法(四)线搜索方法(步长角度;非精确搜索)
机器学习笔记之优化算法——线搜索方法[步长角度,非精确搜索] 引言回顾:精确搜索步长及其弊端非精确搜索近似求解最优步长的条件反例论述 引言 上一节介绍了从精确搜索的步长角度观察了线搜索方法,本节将从非精确搜索的步长角度重新观察线搜…...
![](https://img-blog.csdnimg.cn/c1e8497344504413a2e9e4ca520e451f.png)
Redis 哨兵 (sentinel)
是什么 官网理论:https://redis.io/docs/management/sentinel/ 吹哨人巡查监控后台 master 主机是否故障,如果故障了根据投票数自动将某一个从库转换为新主库,继续对外服务。 作用:无人值守运维 哨兵的作用: 1…...
![](https://www.ngui.cc/images/no-images.jpg)
统计2021年10月每个退货率不大于0.5的商品各项指标
统计2021年10月每个退货率不大于0.5的商品各项指标_牛客题霸_牛客网s mysql(ifnull): select product_id, format(ifnull(sum(if_click)/nullif(count(*),0),0),3) as ctr, format(ifnull(sum(if_cart)/nullif(sum(if_click),0),0),3) as c…...
![](https://img-blog.csdnimg.cn/5d575cb7485a4b4982cac4f937c51e8b.png)
【小波尺度谱】从分段离散小波变换计算小波尺度谱研究(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
![](https://img-blog.csdnimg.cn/b13138e30de74eb5b9164375953f7c14.png)
UE5、CesiumForUnreal加载无高度地形
文章目录 1.实现目标2.实现过程3.参考资料1.实现目标 在UE5中,CesiumForUnreal插件默认的地形都是带高度的,这里加载没有高度的地形,即大地高程为0,GIF动图如下: 2.实现过程 参考官方的教程,下载无高度的DEM,再切片加载到UE中。 (1)下载无高度地形DEM0。 在官方帖子…...
![](https://www.ngui.cc/images/no-images.jpg)
关于Spring中的@Configuration中的proxyBeanMethods属性
Configuration的proxyBeanMethods属性 在Configuration注解中,有两个属性: value配置Bean名称proxyBeanMethos,默认是true 这个proxyBeanMethods的默认属性是true。 直接说:当Configuration注解的proxyBeanMeathods属性是true…...
![](https://www.ngui.cc/images/no-images.jpg)
dp1,ACM暑期培训
D - 摆花 P1077 [NOIP2012 普及组] 摆花 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) Description 小明的花店新开张,为了吸引顾客,他想在花店的门口摆上一排花,共 m 盆。通过调查顾客的喜好,小明列出了顾客最喜欢的 n 种花&…...
![](https://img-blog.csdnimg.cn/img_convert/33eca9fda70e3e6243b4e0c380dcd8bd.png)
大厂程序员的水平比非大厂高很多嘛?
最近一个月,筛选了一百多份简历,前前后后面试了二三十人,基本上都是有大厂经历的人。同时,也录用了几个有大厂经历的。但整体而言,打破了对大厂出来的都是优质人才的幻觉。看到的实际情况与想象中的落差还是比较大的。…...
![](https://img-blog.csdnimg.cn/img_convert/ca51fe1ccdd344a9d6714721500e47fc.png)
Java开发工具MyEclipse发布v2023.1.2,今年第二个修复版!
MyEclipse一次性提供了巨量的Eclipse插件库,无需学习任何新的开发语言和工具,便可在一体化的IDE下进行Java EE、Web和PhoneGap移动应用的开发;强大的智能代码补齐功能,让企业开发化繁为简。 MyEclipse v2023.1.2官方正式版下载 …...
![](https://img-blog.csdnimg.cn/9b6f46d4ced14b5d94cb18f81fdc55ce.jpeg)
基于正交滤波器组的语音DPCM编解码算法matlab仿真
目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 ...........................................................g0zeros(1,lenH); g1zeros(1,l…...
![](https://img-blog.csdnimg.cn/0d7f0587db0e46cda8d65f4f7d2306c6.bmp)
VS2022和QT混合编程打包发布程序
1.在开始菜单输入 CMD 找到 Qt5.15.2(MSVC 64-bit) 2.输入windeployqt exe所在路径 3.运行完毕后,双击打开exe文件,可能会报错,缺少相关的dll,找到缺少的dll拷贝到运行文件夹下即可。...
![](https://img-blog.csdnimg.cn/d40ba3019e2544fb9f7e4c4a696018a9.png#pic_center)
Filebeat学习笔记
Filebeat基本概念 简介 Filebeat是一种轻量级日志采集器,内置有多种模块(auditd、Apache、Nginx、System、MySQL等),针对常见格式的日志大大简化收集、解析和可视化过程,只需一条命令即可。之所以能实现这一点&#…...
![](https://www.ngui.cc/images/no-images.jpg)
【实战】 九、深入React 状态管理与Redux机制(一) —— React17+React Hook+TS4 最佳实践,仿 Jira 企业级项目(十六)
文章目录 一、项目起航:项目初始化与配置二、React 与 Hook 应用:实现项目列表三、TS 应用:JS神助攻 - 强类型四、JWT、用户认证与异步请求五、CSS 其实很简单 - 用 CSS-in-JS 添加样式六、用户体验优化 - 加载中和错误状态处理七、Hook&…...
![](https://www.ngui.cc/images/no-images.jpg)
第九十五回 如何使用dio的转换器
文章目录 概念介绍使用方法使用默认的转换器自定义转换器 示例代码经验分享 我们在上一章回中介绍了"如何打造一个网络框架"相关的内容,本章回中将介绍 如何使用dio的转换器.闲话休提,让我们一起Talk Flutter吧。 概念介绍 转换器主要用来转…...
![](https://img-blog.csdnimg.cn/img_convert/c728ee90f79001251241436617f7c74d.jpeg)
Python深度学习“四大名著”之一【赠书活动|第二期《Python机器学习:基于PyTorch和Scikit-Learn》】
近年来,机器学习方法凭借其理解海量数据和自主决策的能力,已在医疗保健、 机器人、生物学、物理学、大众消费和互联网服务等行业得到了广泛的应用。自从AlexNet模型在2012年ImageNet大赛被提出以来,机器学习和深度学习迅猛发展,取…...
![](https://img-blog.csdnimg.cn/20200508120255164.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1NDMyNjY1,size_16,color_FFFFFF,t_70)
单屏滚动网站/seo服务外包报价
题目描述 农夫约翰要把他的牛奶运输到各个销售点。 运输过程中,可以先把牛奶运输到一些销售点,再由这些销售点分别运输到其他销售点。 运输的总距离越小,运输的成本也就越低。 低成本的运输是农夫约翰所希望的。 不过,他并不想…...
![](http://static.oschina.net/uploads/space/2012/0919/113604_UM60_12.png)
做任务打字赚钱的网站/免费seo网站
参考:http://www.oschina.net/question/12_70587?from20120923 前两天我们分享了 OSChina 的留言表设计说明,今天继续。 用户动态是用户在 OSChina 上做的一些动作,例如提问、回答问题、动弹、评论动弹、发表新闻评论、代码分享、写博客等等…...
![](/images/no-images.jpg)
住房各城乡建设网站/泰安网站seo推广
一、源码特点 1、采用典型的三层架构进行开发、模板分离,支持生成静态 伪静态.、购物车、登陆验证、divcss、js等技术二、功能介绍 1、本源码是一个超市在线购物商城源码,该网上商城是给超市便利店等零售批发实体店定制的网上商城,主要针对周边配送&…...
![](/images/no-images.jpg)
从0开始做网站/百度站长之家
Mat类型简单介绍 /*cv::Mat类是用于保存图像以及其他矩阵的数据结构。默认情况下,其尺寸为0,我们也可以设置其初始尺寸,比如定义一个Mat类的对象,就要写cv::Mat pic(320,640,cv::Scalar(100));Mat类型做为OpenCV2.0新纪元的重要代…...
![](https://images2017.cnblogs.com/blog/1099873/201710/1099873-20171002173229411-1167476103.png)
服装网站建设项目规划书/神马关键词快速排名软件
对于初学的人来说,代码效果和预期的不符合,是一件很心累的事情,因为不知道如何检查。找别人,不认识,不知道找谁,身边有没有认识的人学前端,非常痛苦,如果学前端有什么痛苦的…...
![](/images/no-images.jpg)
几十个必备的设计师灵感网站/惠州网站关键词排名
介绍 github:github.com/apinIron/Li… 由于UI设计需要,模仿了淘宝的收货地址选择对话框,就简单的封装了一个对话框。 使用了TabLayout ViewPager来进行实现,ViewPager中每个页面都是一个RecyclerView。 效果如下: 使…...