一. List类型基础

1.介绍

  它是一个双向链表,支持左进、左出、右进、右出,所以它即可以充当队列使用,也可以充当栈使用。

(1). 队列:先进先出, 可以利用List左进右出,或者右进左出(ListLeftPush和ListRightPop配合 、 ListRightPush和ListLeftPop配合)

(2). 栈:先进后出,可以利用List左进左出,或者右进右出

2. 常用指令Api

3.常用Api

(1). ListLeftPush:从左侧添加,返回集合总数

(2). ListRightPush:从右侧添加,返回集合总数

(3). ListLeftPop:从左侧取1个值,并删除

(4). ListRightPop:从右侧取1个值,并删除

(5). ListInsertBefore:指定的key指定value之前(左边)插入1个值

(6). ListInsertAfter:指定的key指定value之后(右边)插入1个值

(7). ListGetByIndex:获取key的指定索引对应的value值(从左往右算)

(8). ListRange:获取key的所有value,数据类型得一致 (也可以获取指定索引之间的value值,带扩展)

(9). ListLength:获取指定key的数据的个数

(10). ListRemove:删除指定key对应的指定value值,返回删除的个数

(11). ListRightPopLeftPush:从List1右侧取一个值加到List2左侧,返回的是右侧取出来的这个值

代码分享:

             //1.从左侧添加
//单个,返回集合总数
db.ListLeftPush("group1", "你好1");
db.ListLeftPush("group1", "你好2");
db.ListLeftPush("group1", "你好3");
//多个
string[] dList1 = { "你好4", "你好5" };
RedisValue[] redisValue = dList1.Select(u => (RedisValue)u).ToArray();
var d1 = db.ListLeftPush("group1", redisValue); //2.从右侧添加
db.ListRightPush("group1", "你好6"); //3.从左侧取1个值,并删除
//var v1=db.ListLeftPop("group1"); //4.从右侧取1个值并删除
//var v2 = db.ListRightPop("group1"); //5. 在List的指定的key指定value之前(左边)插入1个值
db.ListInsertBefore("group1", "你好3", "ypf001"); //6. 在List的指定的key指定value之后(右边)插入1个值
db.ListInsertAfter("group1", "你好3", "ypf002"); //7. 获取key指定索引的值(从左往右算)
var d2 = db.ListGetByIndex("group1", );
var d3 = db.ListGetByIndex("group1", ); //8. 获取key的所有数据,数据类型得一致
var d4 = db.ListRange("group1").Select(u => (string)u).ToList();
//获取key的前4条数据(从左往右)
var d44 = db.ListRange("group1", , ).Select(u => (string)u).ToList(); //9.获取指定key的数据的个数
long d5 = db.ListLength("group1"); //10. 删除指定key对应的指定value值,返回删除的个数
db.ListLeftPush("group1", "你好");
db.ListLeftPush("group1", "你好");
long d6 = db.ListRemove("group1", "你好"); //11. 从List1右侧取一个值加到List2左侧,返回的是右侧取出来的这个值
db.ListLeftPush("group2", "你好1");
db.ListLeftPush("group2", "你好2");
db.ListLeftPush("group2", "你好3");
db.ListLeftPush("group3", "哈哈1");
db.ListLeftPush("group3", "哈哈2");
db.ListLeftPush("group3", "哈哈3");
//从队列group2右侧取出来一个值放到group3中
var d7 = db.ListRightPopLeftPush("group2", "group3");

二. 案例分析

(一). 消息队列 (生产者消费者模式)

PS:生产者消费模式:可以是多个生产者,多个消费者,但是生成的数据按顺序进入队列,但是每个数据只能被一个消费者消费。

1. 异步处理

  (1). 将同步业务:创建订单→增加积分→发送短信,改为创建订单后 存放到两个消息队列中(积分队列和短信队列),然后积分业务和短信业务分部去队列中读取,执行各自的业务

  (2). 注册成功发邮件通知:很多场景注册成功后要给用户发一封邮件提示,但这封邮件实时性要求并不是很高,而且发邮件一般是调用第三方接口进行发送,有时候可能会很慢或者故障了, 针对这种情况,借助队列采用生产者消费者模式非常适合。

2. 应用解耦

  将原先订单系统和库存系统的强依赖关系,改为中间引入消息队列,这样二者都依赖消息队列做中介.

3. 流量削锋

  秒杀服务,下单的用户加到队列中,然后开启另外一个线程从队列中读取进行下单,下单成功/失败 利用实时通讯技术通知客户端 或者 客户端主动刷新页面进行查看结果,这里要结合实际架构(单体or集群)分析秒杀情况,不能一概而论,详见后面秒杀章节。

4. 即时通讯

  考虑到同时很多人发送,前端页面的渲染会有点吃不消,这里可以采用 群id 当做队列的key,发送的消息当做value,存入队列中,然后开启一个新的线程从里面读取, 可以一下获取20条,获取的同时并删除,如果队列为空,则休息几秒中,再次获取。

针对群聊的代码分享

  以群聊为例,利用ListLeftPush方法,以“群id”当做key,以发送人id、发送内容、时间组合当做value,从左侧存储到队列;然后利用Core中的BackService类开启后台线程利用ListRightPop 进行读取,同时要在ConfigureService中进行注册。

代码分享:

        /// <summary>
/// 测试群聊页面
/// (PS:不断刷新即可)
/// </summary>
/// <returns></returns>
public IActionResult Index()
{
string userId = Guid.NewGuid().ToString("N");
string msg = "哈哈" + new Random().Next(, );
SendMessage(userId, msg);
return View();
} /// <summary>
///群聊发送消息接口
/// </summary>
/// <param name="userId">用户id</param>
/// <param name="msg">发送的内容</param>
/// <returns></returns>
public string SendMessage(string userId, string msg)
{
try
{
string groupName = "classParty"; //群名
string sendContent = $"{userId}_{msg}_{DateTime.Now}"; //内容
//存入队列
_redis.ListLeftPush(groupName, sendContent);
return "ok";
}
catch (Exception ex)
{
return "error";
}
}

后台服务及注册:

  public class SendService : BackgroundService
{
private readonly IDatabase _redis;
public SendService(RedisHelp redisHelp)
{
_redis = redisHelp.GetDatabase();
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
try
{
//实际情况,这里有几个群,开几个线程执行
List<string> msgList = new List<string>();
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
//要么没有更多待发消息立即发给客户端,要么累积满1秒钟待发消息后发送给客户端
while (true)
{
string msg = _redis.ListRightPop("classParty");
if (!string.IsNullOrEmpty(msg))
{
msgList.Add(msg);
}
else
{
await Task.Delay();
}
//满一段时间的消息向客户端发送
if (stopwatch.Elapsed>TimeSpan.FromSeconds())
{
stopwatch.Stop();
if (msgList.Any())
{
//将这一批消息发送给客户端
//需要重新滞空msgList
}
}
}
}
catch (Exception)
{
throw;
}
}
}
}
  public void ConfigureServices(IServiceCollection services)
{
//注册后台服务
services.AddHostedService<SendService>();
}

(二). 解决查询缓慢问题

  比如发帖网站,会有非常多的帖子,而且数量每日俱增,首页显示的是最新发布的10条帖子,显示的是:发帖人名称 和 发帖标题,如果从数据库中查询可能会非常慢,这时候可以把发帖人名称和

发帖标题(包括帖子id),存到Redis队列中,这个时候利用 栈 的特性,ListGetByIndex:获取key指定索引的值(从左往右算), 获取前10条数据,用于显示,查看详情的时候,再根据帖子的id到数据库中查。

三. 发布订阅模式

 1. 说明

  发布者发布一条消息,所有的订阅者都能收到。

2. 案例背景

  以微博为例(或者微信的订阅号),博主A,博主B都关注了博主C、博主D,在博主A(或B)的版面,应该显示的是博主C和博主D发布的最新博文(最新发布的在最上面),换句话说博主C或者博主D每发一篇博文,都要推送给关注他们的博主A和博主B。

3. 技术分析

(1). 数据结构的设计:一个博主对应一个List链表,用来存储该博主应该显示的博文消息。 以博主的用户id作为key,博文消息的id作为value。

(2). 博主C每发一条博文,就需要向关注他的粉丝(A和B)对应的链表中分别存储一下 该博文消息的id。

(3). 博主D每发一条博文,就需要向关注他的粉丝(A和B)对应的链表中分别存储一下 该博文消息的id。

(4).  博主A就可以到自己对应的链表中利用的特性,获取最新的n条博文消息id。

PS: 拿到博文消息id了,剩下的就容易了,根据id去关系型数据中查内容就很快了,或者也可以将标题或者内容的前100字也存储到Redis中,便于页面显示(这样value的格式就是:博文id-博文标题-博文内容前100字)。

!

  • 作       者 : Yaopengfei(姚鹏飞)
  • 博客地址 : http://www.cnblogs.com/yaopengfei/
  • 声     明1 : 本人才疏学浅,用郭德纲的话说“我是一个小学生”,如有错误,欢迎讨论,请勿谩骂^_^。
  • 声     明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
 

第三节: List类型的介绍、生产者消费者模式、发布订阅模式的更多相关文章

  1. 阶段5 3.微服务项目【学成在线】_day05 消息中间件RabbitMQ_8.RabbitMQ研究-工作模式-发布订阅模式-生产者

    Publish/subscribe:发布订阅模式 发布订阅模式: 1.每个消费者监听自己的队列. 2.生产者将消息发给broker,由交换机将消息转发到绑定此交换机的每个队列,每个绑定交换机的队列都将 ...

  2. 阶段5 3.微服务项目【学成在线】_day05 消息中间件RabbitMQ_9.RabbitMQ研究-工作模式-发布订阅模式-消费者

    消费者需要写两个消费者 定义邮件的类 复制以前的代码到邮件类里面进行修改 最上面 声明队列的名称和交换机的名称 监听修改为email 的队列的名称 手机短信接收端 复制一份email的接收端的代码 改 ...

  3. python使用rabbitMQ介绍三(发布订阅模式)

    一.模式介绍 在前面的例子中,消息直接发送到queue中. 现在介绍的模式,消息发送到exchange中,消费者把队列绑定到exchange上. 发布-订阅模式是把消息广播到每个消费者,每个消费者接收 ...

  4. 生产者-消费者模型在Hudi中的应用

    介绍 生产者-消费者模型用于解耦生产者与消费者,平衡两者之间的能力不平衡,该模型广泛应用于各个系统中,Hudi也使用了该模型控制对记录的处理,即记录会被生产者生产至队列中,然后由消费者从队列中消费,更 ...

  5. JMS消息传递类型特点介绍

    对于消息的传递有两种类型: 一种是点对点的,即一个生产者和一个消费者一一对应: 另一种是发布/ 订阅模式,即一个生产者产生消息并进行发送后,可以由多个消费者进 行接收. 特点介绍: 点到点模型点对点传 ...

  6. labview学习——生产者/消费者(数据)(事件)

    其主要的模型: 主要从以下几个方面理解: 1.可重入性 正常的labview是多线程设计语言,而我们在执行VI时的规则是通过VI的命名来分别调用实现的. 打开VI的Highlight调试工具,可以看出 ...

  7. 生产者消费者模型及Golang简单实现

    简介:介绍生产者消费者模型,及go简单实现的demo. 一.生产者消费者模型 生产者消费者模型:某个模块(函数等〉负责产生数据,这些数据由另一个模块来负责处理(此处的模块是广义的,可以是类.函数.协程 ...

  8. Java实现生产者消费者问题与读者写者问题

    摘要: Java实现生产者消费者问题与读者写者问题 1.生产者消费者问题 生产者消费者问题是研究多线程程序时绕不开的经典问题之一,它描述是有一块缓冲区作为仓库,生产者可以将产品放入仓库,消费者则可以从 ...

  9. 4.生产者 消费者模式的RabbitMQ

    1.生产者: using RabbitMQ.Client; using System; using System.Text; namespace Publisher1 { class Program ...

随机推荐

  1. pandas.read_sql_query()读取数据库数据用chunksize的坑

    最近一项工作需要读取数据库中1500万条数据,考虑到数据量太大,不方便直接一次性读取,不然会内存爆炸.想到用pandas.read_sql_query()里有一个chunksize可以分批返回chun ...

  2. 黄聪:不使用 webpack,vuejs 异步加载模板

    webpack 打包不会玩,整了这么个小玩具 一段 vue 绑定代码,关键点在 gmallComponent 1.异步加载外部 vue 文件(非 .vue) 2.按一定规则拆分 template.sc ...

  3. Python3---爬虫---抓取百度贴吧

    前言 该文章主要描述如何抓取百度贴吧内容.当然是简单爬虫实现功能,没有实现输入参数过滤等辅助功能,仅供小白学习. 修改时间:20191219 天象独行 import os,urllib.request ...

  4. Java生鲜电商平台-SpringCloud微服务开发中的数据架构设计实战精讲

    Java生鲜电商平台-SpringCloud微服务开发中的数据架构设计实战精讲 Java生鲜电商平台:   微服务是当前非常流行的技术框架,通过服务的小型化.原子化以及分布式架构的弹性伸缩和高可用性, ...

  5. Python【day 14-3】二分法查找

    #二分法查找 #方法1 循环+左右边界变动,两者差减半 #方法2 递归+新列表长度减半 #方法3 递归+左右边界变动,两者差减半 #方法1 循环+左右边界变动,两者差减半 def recursion1 ...

  6. AppBoxFuture(八): 另类的ORM实现

      通常的ORM实现基于配置或注释,由反射或Emit生成相应的Sql语句,然后将Sql发送给数据库解析Sql字符串生成AST再交给优化器处理后执行,返回的数据再经由反射或Emit转换为相应的实体实例. ...

  7. export default和export的使用

    export default和export都是用来向外暴露成员 export default 向外暴露的成员可以使用任意的变量来接收,在一个模块中,export default只允许向外暴露一次,可以 ...

  8. Java 方法引用_特性

    JAVA8 方法引用:(四种方法引用的使用) 对象引用的特点:不同的对象可以操作同一块的内容:而方法引用就是指为一个方法设置别名,相当于一个方法定义了不同的名字. 引用静态方法: 类名称 :: sta ...

  9. 剑指offer 19:二叉树的镜像

    题目描述 操作给定的二叉树,将其变换为源二叉树的镜像.   输入描述:   解题思路 这一问题明显,在进行递归遍历节点时,将根节点的左右子树进行交换,因此完成树的遍历即可.   C++实现代码 /* ...

  10. 3.智能快递柜(通信篇-HTTP)

    1.智能快递柜(开篇) 2.智能快递柜(终端篇) 3.智能快递柜(通信篇-HTTP) 4.智能快递柜(通信篇-SOCKET) 5.智能快递柜(通信篇-Server程序) 6.智能快递柜(平台篇) 7. ...