当前位置: 首页 > news >正文

使用Redis构建简易社交网站(3)-状态与信息流

目的

本文目的:实现获取主页时间线和状态推送功能。(完整代码附在文章末尾)

相关知识

在我上一篇文章 《使用Redis构建简易社交网站(2)-处理用户关系》中提到了实现用户关注和取消关注功能。

那这篇文章将教会你掌握:1redis基本命令,2python基本命令。

redis基本命令

zadd:将成员加入到有序集合中,并确保其在正确的位置上。

conn = redis.Redis()
conn.zadd("testzset", "member2", 3)
conn.zadd("testzset", "member1", 2)
conn.zadd("testzset", "member3", 1)

执行后:

  1. member3
  2. member1
  3. member2

执行结果:111

zrange:返回有序集合中指定区间内的成员。

conn = redis.Redis()
conn.zrange("testzset", 0, 1)

执行结果:['member3', 'member1']

zrevrange:按分值递减的顺序返回有序集合中指定区间内的成员。

conn = redis.Redis()
conn.zrevrange("testzset", 0, -1)

执行结果:['member2', 'member1', 'member3']

hgetall:返回哈希表中所有的域-值对。

conn = redis.Redis()
conn.hgetall("testhash")

执行结果:{'field1': '2'}

hget:从哈希中获取指定域的值。

conn = redis.Redis()
conn.hget("testhash", "field1")

执行结果:2

pipeline:将多条命令按照先后顺序放进一个队列中,一般配合execute一同使用,原子性(atomic)地执行队列里的命令。

conn = redis.Redis()
pipe = conn.pipeline(True) # 事务开始
pipe.incr("counter")
pipe.incr("counter")
pipe.incr("counter")
pipe.execute() # 事务执行

执行结果:[1, 2, 3],通过下标即可获取对应命令的执行结果。

python基本命令

使用格式化拼接字符串:

"My name is %s, I'm %i years old"%('educoder', 2)

执行结果:"My name is educoder, I'm 2 years old"

将字符串转换为浮点数:

float("1.23")

执行结果:1.23

实战例题

编写 get_home_timeline(uid) 函数,实现获得主页时间线的功能,具体参数与要求如下:

  • 方法参数uid为要获取主页时间线的用户编号;
  • 获取动态编号的实现:从存储用户主页时间线的有序集合home:{uid}中按照分值递减的顺序取出所有成员;
  • 获取动态详情的实现:遍历动态编号,使用事务一次性获取每个动态编号对应动态详情哈希键post:{pid}的所有域-值对;
  • 返回主页时间线的实现:返回事务执行的结果。

编写 post(uid, content) 函数,实现发布动态并将动态推送给粉丝的功能,具体参数与要求如下:

  • 方法参数uid为要发布动态的用户编号,content为要发布的动态内容;
  • 发布动态的实现:调用第一关中实现的create_post方法,并接收返回的动态编号,若发布失败,则取消发布,返回None
  • 获取发布时间的实现:从新发布的动态编号对应的动态详情哈希键post:{pid}中获取posted域;
  • 更新个人主页的实现:将新发布的动态编号存储到个人主页有序集合键profile:{uid}中,分值为转为浮点数后的发布时间;
  • 更新粉丝主页时间线的实现:遍历用户的粉丝列表followers:{uid},将新发布的动态编号存储到每个粉丝的主页时间线的有序集合home:{follower_id}中,分值为转为浮点数后的发布时间;
  • 返回发布结果的实现:返回新发布的动态编号。
测试说明

测试输入:4

预期输出:

用户 4 关注 用户 1
关注结果: True测试 post 方法...
创建动态: 1
创建动态: 2
用户 1 的动态列表: ['2', '1']
用户 4 的主页时间线动态编号: ['2', '1']测试 get_home_timeline 方法...
用户 4 的主页时间线: [{'content': 'NEW post from user 1!!!', 'uid': '1', 'user_name': 'test_user1', 'id': '2'}, {'content': 'This is the first post from user 1', 'uid': '1', 'user_name': 'test_user1', 'id': '1'}]

code.py

#code.py
#-*- coding:utf-8 -*-import re
import time
import redisconn = redis.Redis()# 获得主页时间线
def get_home_timeline(uid, page=1, count=30):# 请在下面完成要求的功能#********* Begin *********#post_ids = conn.zrevrange("home:%s"%(uid), 0, -1)pipe = conn.pipeline(True)for pid in post_ids:pipe.hgetall("post:%s"%(pid))return pipe.execute()#********* End *********## 发布动态并将动态推送给粉丝
def post(uid, content):# 请在下面完成要求的功能#********* Begin *********#pid = create_post(uid, content)if not pid:return Noneposted = conn.hget("post:%s"%(pid), "posted")conn.zadd("profile:%s"%(uid), pid, float(posted))followers = conn.zrange("followers:%s"%(uid), 0, -1)pipe = conn.pipeline(False)for follower in followers:pipe.zadd("home:%s"%(follower), pid, float(posted))pipe.execute()return pid#********* End *********## 关注用户
def follow(uid, other_uid):fkey1 = "following:%s"%(uid)fkey2 = "followers:%s"%(other_uid)if conn.zscore(fkey1, other_uid):return Nonenow = time.time()pipe = conn.pipeline(True)pipe.zadd(fkey1, other_uid, now)pipe.zadd(fkey2, uid, now)following, followers = pipe.execute()posts = conn.zrevrange("profile:%s"%(other_uid), 0, 100, withscores=True)if posts:pipe.zadd("home:%s"%(uid), **dict(posts))pipe.hincrby("user:%s"%(uid), 'following', int(following))pipe.hincrby("user:%s"%(other_uid), 'followers', int(followers))pipe.execute()return True# 取消关注
def unfollow(uid, other_uid):fkey1 = "following:%s"%(uid)fkey2 = "followers:%s"%(other_uid)if not conn.zscore(fkey1, other_uid):return Nonepipe = conn.pipeline(True)pipe.zrem(fkey1, other_uid)pipe.zrem(fkey2, uid)following, followers = pipe.execute()posts = conn.zrevrange("profile:%s"%(other_uid), 0, -1)if posts:pipe.zrem("home:%s"%(uid), *posts)pipe.hincrby("user:%s"%(uid), 'following', -int(following))pipe.hincrby("user:%s"%(other_uid), 'followers', -int(followers))pipe.execute()return True# 创建新用户
def create_user(login_name, real_name):login_name = login_name.lower()if conn.hget("users", login_name):return Noneuid = conn.incr("user:id")pipe = conn.pipeline(True)pipe.hset("users", login_name, uid)pipe.hmset("user:%i"%(uid), {'login_name': login_name,'id': uid,'real_name': real_name,'followers': 0,'following': 0,'posts': 0,'last_signup': time.time(),})pipe.execute()return uid# 为用户创建新动态
def create_post(uid, content):pipe = conn.pipeline(True)pipe.hget("user:%i"%(uid), 'login_name')pipe.incr("post:id")login_name, pid = pipe.execute()if not login_name:return Nonepipe.hmset("post:%i"%(pid), {'id': pid,'uid': uid,'content': content,'posted': time.time(),'user_name': login_name,})pipe.hincrby("user:%i"%(uid), 'posts')pipe.execute()return pid

 read.py

#read.py
#-*- coding:utf-8 -*-import os
import sys
import time
import redis
import pprint
from code import *conn = redis.Redis()
retry_time = 0
while True:try:conn.ping()breakexcept redis.exceptions.ConnectionError:os.system("redis-server > /dev/null 2>&1 &")retry_time += 1if retry_time > 3:breakpipe = conn.pipeline(True)
pipe.delete("users", "user:id")
keys = (conn.keys("user:*") + conn.keys("followers:*") + conn.keys("following:*") +conn.keys("post:*") + conn.keys("profile:*") + conn.keys("home:*")
)
if keys:pipe.delete(*keys)
pipe.execute()# 创建测试数据
join_str = " "
for i in xrange(10):login_name = "test_user%i"%(i+1)real_name = join_str.join(login_name.split("_")).capitalize()create_user(login_name, real_name)uid = int(sys.stdin.readline().strip())print "用户 %i 关注 用户 1"%(uid)
f_result = follow(uid, 1)
print "关注结果: " + str(f_result)
printprint "测试 post 方法..."
content = "This is the first post from user 1"
pid = post(1, content)
print "创建动态: " + str(pid)
content = "NEW post from user 1!!!"
pid = post(1, content)
print "创建动态: " + str(pid)
my_profile = conn.zrevrange("profile:1", 0, -1)
print "用户 1 的动态列表: " + str(my_profile)
home_timeline = conn.zrevrange("home:%i"%(uid), 0, -1)
print "用户 %i 的主页时间线动态编号: "%(uid) + str(home_timeline)
printprint "测试 get_home_timeline 方法..."
my_home = get_home_timeline(uid)
for info in my_home:info.pop("posted", "404")
print "用户 %i 的主页时间线: "%(uid) + str(my_home)

相关文章:

使用Redis构建简易社交网站(3)-状态与信息流

目的 本文目的:实现获取主页时间线和状态推送功能。(完整代码附在文章末尾) 相关知识 在我上一篇文章 《使用Redis构建简易社交网站(2)-处理用户关系》中提到了实现用户关注和取消关注功能。 那这篇文章将教会你掌握:1&#x…...

Python,非二进制的霍夫曼编码

一般来说,霍夫曼编码是二进制的,但是非二进制的也可以。本文中,通过修改N,可以得到任意进制的霍夫曼编码。 非二进制编码的作用:例如,设计九键输入法,希望根据拼音的概率来编码,常用…...

详解—[C++数据结构]—红黑树

目录 一、红黑树的概念 ​编辑二、红黑树的性质 三、红黑树节点的定义 四、红黑树结构 五、红黑树的插入操作 5.1. 按照二叉搜索的树规则插入新节点 5.2、检测新节点插入后,红黑树的性质是否造到破坏 情况一: cur为红,p为红,g为黑&…...

甘草书店记:6# 2023年10月31日 星期二 「梦想从来不是一夜之间实现的」

甘草书店 今天收到甘草书店第二版装修设计平面图,与理想空间越来越近。 于我而言,每一次世俗意义上所谓的成功都不如文艺作品中表现的那样让人欢腾雀跃。当你用尽120分努力,达到了冲刺满分的实力时,得个优秀的成绩也并不意外。 …...

基于Java SSM车辆租赁管理系统

现代生活方式下,人们经常需要租赁车辆,比如婚庆、自驾游等,车辆租赁公司应运而生,车辆租赁管理系统就是借助计算机对车辆租赁情况进行全面管理。系统的主要管理对象及操作有: 车辆信息:包括车辆类型、车辆名…...

侯捷C++八部曲(一,面向对象)

头文件和类的声明 inline inline修饰函数,是给编译器的一个建议,到底是否为inline由编译器来决定,inline修饰的函数在使用时是做简单的替换,这样就避免了一些函数栈空间的使用,从能提升效率。从另一种角度看&#xff…...

《数据库系统概论》学习笔记——王珊 萨师煊

第一章 绪论 一、数据库系统概述 1.数据库的4个基本概念 (1)数据 描述事物的符号记录称为数据 (2)数据库 存放数据的仓库 (3)数据库管理系统 主要功能: (1)数据定…...

关于使用百度开发者平台处理语音朗读问题排查

错误信息:"convert_offline": false, "err_detail": "16: Open api characters limit reach 需要领取完 识别和合成都要有...

安全认证 | CISP和CISP-PTE的区别在哪里?

CISP和CISP-PTE的区别在哪里? 在国内安全信息认证体系中,虽然CISP认证与CISP-PTE认证都是中国信息安全测评中心负责颁发,均获得政府背景的认可,但二者还是有区别的。 今天就详细为大家介绍一下。 01 定义不同 ★ 注册信息安全专…...

Unity3D 导出的apk进行混淆加固、保护与优化原理(防止反编译)

​ 目录 前言: 准备资料: 正文: 1:打包一个带有签名的apk 2:对包进行反编译 3:使用ipaguard来对程序进行加固 前言: 对于辛辛苦苦完成的apk程序被人轻易的反编译了,那就得不偿…...

C语言扫雷小游戏

以下是一个简单的C语言扫雷小游戏的示例代码&#xff1a; #include <stdio.h>#include <stdlib.h>#include <time.h>#define BOARD_SIZE 10#define NUM_MINES 10int main() { int board[BOARD_SIZE][BOARD_SIZE]; int num_flags, num_clicks; int …...

用取样思想一探AIX上进程性能瓶颈

本篇文章也是我在解决客户问题时的一些思路&#xff0c;希望对读者有用。 本文与GDB也与DBX&#xff08;AIX上的调试工具&#xff09;无关&#xff0c;只是用到了前文《GDB技巧》中的思想&#xff1a;取样思想 客户问题&#xff1a; 原始问题是磁盘被占满了&#xff0c;通过…...

分布式搜索引擎elasticsearch(二)

1.DSL查询文档 elasticsearch的查询依然是基于JSON风格的DSL来实现的。 1.1.DSL查询分类 Elasticsearch提供了基于JSON的DSL(Domain Specific Language)来定义查询。常见的查询类型包括: 查询所有:查询出所有数据,一般测试用。例如:match_all 全文检索(full text)查…...

Tecplot绘制涡结构(Q准则)

文章目录 目的步骤1步骤2步骤3步骤4步骤5步骤6结果 目的 Tecplot绘制涡结构(Q准则判别)并用温度进行染色 Q准则计算公式 步骤1 步骤2 步骤3 步骤4 步骤5 步骤6 结果...

Whisper

文章目录 使后感Paper Review个人觉得有趣的Log Mel spectrogram & STFT Trainingcross-attention输入cross-attention输出positional encoding数据 Decoding为什么可以有时间戳的信息 Test code 使后感 因为运用里需要考虑到时效和准确性&#xff0c;类似于YOLO&#xff…...

Android系统分析

Android工程师进阶第八课 AMS、WMS和PMS 一、Binder通信 【Android Framework系列】第2章 Binder机制大全_android binder-CSDN博客 Android Binder机制浅谈以及使用Binder进行跨进程通信的俩种方式&#xff08;AIDL以及直接利用Binder的transact方法实现&#xff09;_bind…...

五、关闭三台虚拟机的防火墙和Selinux

目录 1、关闭每台虚拟机的防火墙 2、关闭每台虚拟机的Selinux 2.1 什么是SELinux...

【从零开始学习Redis | 第六篇】爆改Setnx实现分布式锁

前言&#xff1a; 在Java后端业务中&#xff0c; 如果我们开启了均衡负载模式&#xff0c;也就是多台服务器处理前端的请求&#xff0c;就会产生一个问题&#xff1a;多台服务器就会有多个JVM&#xff0c;多个JVM就会导致服务器集群下的并发问题。我们在这里提出的解决思路是把…...

Kubernetes学习笔记-Part.05 基础环境准备

目录 Part.01 Kubernets与docker Part.02 Docker版本 Part.03 Kubernetes原理 Part.04 资源规划 Part.05 基础环境准备 Part.06 Docker安装 Part.07 Harbor搭建 Part.08 K8s环境安装 Part.09 K8s集群构建 Part.10 容器回退 第五章 基础环境准备 5.1.SSH免密登录 在master01、…...

语义分割 DeepLab V1网络学习笔记 (附代码)

论文地址&#xff1a;https://arxiv.org/abs/1412.7062 代码地址&#xff1a;GitHub - TheLegendAli/DeepLab-Context 1.是什么&#xff1f; DeepLab V1是一种基于VGG模型的语义分割模型&#xff0c;它使用了空洞卷积和全连接条件随机&#xff08;CRF&#xff09;来提高分割…...

【JavaEE】-- HTTP

1. HTTP是什么&#xff1f; HTTP&#xff08;全称为"超文本传输协议"&#xff09;是一种应用非常广泛的应用层协议&#xff0c;HTTP是基于TCP协议的一种应用层协议。 应用层协议&#xff1a;是计算机网络协议栈中最高层的协议&#xff0c;它定义了运行在不同主机上…...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)

文章目录 1.什么是Redis&#xff1f;2.为什么要使用redis作为mysql的缓存&#xff1f;3.什么是缓存雪崩、缓存穿透、缓存击穿&#xff1f;3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...

相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解

【关注我&#xff0c;后续持续新增专题博文&#xff0c;谢谢&#xff01;&#xff01;&#xff01;】 上一篇我们讲了&#xff1a; 这一篇我们开始讲&#xff1a; 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下&#xff1a; 一、场景操作步骤 操作步…...

PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建

制造业采购供应链管理是企业运营的核心环节&#xff0c;供应链协同管理在供应链上下游企业之间建立紧密的合作关系&#xff0c;通过信息共享、资源整合、业务协同等方式&#xff0c;实现供应链的全面管理和优化&#xff0c;提高供应链的效率和透明度&#xff0c;降低供应链的成…...

基础测试工具使用经验

背景 vtune&#xff0c;perf, nsight system等基础测试工具&#xff0c;都是用过的&#xff0c;但是没有记录&#xff0c;都逐渐忘了。所以写这篇博客总结记录一下&#xff0c;只要以后发现新的用法&#xff0c;就记得来编辑补充一下 perf 比较基础的用法&#xff1a; 先改这…...

【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验

系列回顾&#xff1a; 在上一篇中&#xff0c;我们成功地为应用集成了数据库&#xff0c;并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了&#xff01;但是&#xff0c;如果你仔细审视那些 API&#xff0c;会发现它们还很“粗糙”&#xff1a;有…...

拉力测试cuda pytorch 把 4070显卡拉满

import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试&#xff0c;通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小&#xff0c;增大可提高计算复杂度duration: 测试持续时间&#xff08;秒&…...

STM32HAL库USART源代码解析及应用

STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...

Web中间件--tomcat学习

Web中间件–tomcat Java虚拟机详解 什么是JAVA虚拟机 Java虚拟机是一个抽象的计算机&#xff0c;它可以执行Java字节码。Java虚拟机是Java平台的一部分&#xff0c;Java平台由Java语言、Java API和Java虚拟机组成。Java虚拟机的主要作用是将Java字节码转换为机器代码&#x…...

wpf在image控件上快速显示内存图像

wpf在image控件上快速显示内存图像https://www.cnblogs.com/haodafeng/p/10431387.html 如果你在寻找能够快速在image控件刷新大图像&#xff08;比如分辨率3000*3000的图像&#xff09;的办法&#xff0c;尤其是想把内存中的裸数据&#xff08;只有图像的数据&#xff0c;不包…...