day11--RabbitMQ、Redis
RabbitMQ:就是消息队列与Python里面的queue功能类似。线程和进程queue只能Python自己使用;不同机器和程序传递消息就要使用RabbitMQ了,中间传递。
RabbitMQ的功能与Queue的功能一样,不同的是,线程queue.Queue()用来不同线程之间进行传递消息;进程Queue()用来子进程和父进程之间的数据交互;或者同属于同一父进程下多个子进程进行交互。
RabbitMQ可以实现多个程序之间的数据交互,不需要让程序去各自维护,统一通过中间商,RabbitMQ实现即可。
RabbitMQ地址:(http://erlang.org/download/?S=A/snapshots/otp_src_R14B01.readme/otp_doc_man_R16A_RELEASE_CANDIDATE.tar.gz/otp_win32_R10B-1a.exe/otp_doc_html_R16B.tar.gz/otp_doc_man_R10B-5.tar.gz)
RabbitMQ是使用erlang开发的
RabbitMQ队列
安装 http://www.rabbitmq.com/install-standalone-mac.html
安装python rabbitMQ module
pip install pika
easy_install pika
https:
/
/
pypi.python.org
/
pypi
/
pika
实现最简单的队列通信
由于Linux电脑尝试了很多次,配置没有弄好,参考网址:https://www.cnblogs.com/alex3714/articles/5248247.html
send端
import pika connection = pika.BlockingConnection(pika.ConnectionParameters( 'localhost')) channel = connection.channel() #声明一个管道 #声明queue channel.queue_declare(queue='hello') #声明一个"hello"的queue #n RabbitMQ a message can never be sent directly to the queue, it always needs to go through an exchange. channel.basic_publish(exchange='', routing_key='hello', body='Hello World!') #routing_key是queue的名称 print(" [x] Sent 'Hello World!'") connection.close()
receive端
import pika connection = pika.BlockingConnection(pika.ConnectionParameters( 'localhost')) channel = connection.channel() #You may ask why we declare the queue again ‒ we have already declared it in our previous code. # We could avoid that if we were sure that the queue already exists. For example if send.py program #was run before. But we're not yet sure which program to run first. In such cases it's a good # practice to repeat declaring the queue in both programs. channel.queue_declare(queue='hello') def callback(ch, method, properties, body): print(" [x] Received %r" % body) channel.basic_consume(callback, #如果收到消息,就调用callback函数来处理消息 queue='hello', #从那个队列里面接收消息 no_ack=True) #不确认,no_ack=True,服务器端不确认; print(' [*] Waiting for messages. To exit press CTRL+C') channel.start_consuming()
Work Queues
在这种模式下,RabbitMQ会默认把p发的消息依次分发给各个消费者(c),跟负载均衡差不多
Redis操作(http://www.cnblogs.com/wupeiqi/articles/5132791.html)(http://www.cnblogs.com/alex3714/articles/6217453.html)(https://www.cnblogs.com/alex3714/articles/5248247.html)
正常程序之间可以通过json和pickle传递数据,是通过文件。但是文件之间传输效率太低了。因此引入了缓存,缓存是放在内存中(硬盘效率太低),因此找一个中间媒介。现在常用的就是redis,下面来了解一下:
redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在次基础上实现了master-slave(主从)同步。
Redis优点
1.异常快速 : Redis是非常快的,每秒可以执行大约110000设置操作,81000个/每秒的读取操作;
2.支持丰富的数据类型 : Redis支持最大多数开发人员已经知道如列表,集合,可排序集合,哈希等数据类型;这使得在应用中很容易解决的各种问题,因为我们知道哪些问题处理使用哪种数据类型更好解决;
3.操作都是原子的 : 所有 Redis 的操作都是原子,从而确保当两个客户同时访问 Redis 服务器得到的是更新后的值(最新值);
4.MultiUtility工具:Redis是一个多功能实用工具,可以在很多如:缓存,消息传递队列中使用(Redis原生支持发布/订阅),在应用程序中,如:Web应用程序会话,网站页面点击数等任何短暂的数据;
安装Redis环境
一、Redis安装和基本使用
1 wget http://download.redis.io/releases/redis-3.0.6.tar.gz 2 tar xzf redis-3.0.6.tar.gz 3 cd redis-3.0.6 4 make
启动服务端
src/redis-server
启动客户端
1 src/redis-cli 2 redis> set foo bar 3 OK 4 redis> get foo 5 "bar"
二、Python操作Redis
Python操作Redis
sudo pip install redis or sudo easy_install redis or 源码安装 详见:https://github.com/WoLpH/redis-py
缓存里面的数据是共享的,是存储在内存中,硬盘的效率太低,redis缓存也是通过socket基础原理来实现数据的共享。redis就是一个类似字典key-value的缓存系统。
API使用
redis-py 的API的使用可以分类为:
1.连接方式
2.连接池
3.操作
String 操作 #简单的keys-value操作
Hash 操作
List 操作
Set 操作
Sort Set 操作 #有序集合
4.管道
5.发布订阅
1、操作模式
redis-py提供两个类Redis和StrictRedis用于实现Redis的命令,StrictRedis用于实现大部分官方的命令,并使用官方的语法和命令,Redis是StrictRedis的子类,用于向后兼容旧版本的redis-py。
import redis r = redis.Redis(host='10.211.55.4', port=6379) #连接IP地址和端口号 r.set('foo', 'Bar') print r.get('foo')
使用redis设置属性:
127.0.0.1:6379> set name alex
OK
127.0.0.1:6379> set age 22
OK
set设置 name名字 alex值
keys *查看属性
get来获取属性值(get name、get age)实现了两个程序之间的数据共享,QQ、微信都能来取数据。 如果使用get获取属性,属性不存在,则为空,如下:
127.0.0.1:6379> get name
"alex"
127.0.0.1:6379> get foo
"bar"
127.0.0.1:6379> get alex
(nil)
127.0.0.1:6379> get age
"22"
set使用方式:
set name alex ex 2中,ex 2代表设置存活时间,2代表两秒,exists存在。set设置属性的存活时间。
2、连接池
redis-py使用connection pool来管理对一个redis server的所有连接,避免每次建立、释放连接的开销。默认,每个Redis实例都会维护一个自己的连接池。可以直接建立一个连接池,然后作为参数Redis,这样就可以实现多个Redis实例共享一个连接池。经常取数据,建立socket连接,建立连接池,从池子里面取数据。
import redis
pool = redis.ConnectionPool(host="127.0.0.1",port=6379) #设置一个连接池,所有程序都从这个池子里面取数据
r = redis.Redis(connection_pool=pool) #建立一个连接实例
r.set("school","oldboy")
print(r.get("school"))
运行结果如下:
b'oldboy'
set(name, value, ex=None, px=None, nx=False, xx=False)
在Redis中设置值,默认,不存在则创建,存在则修改
参数:
ex,过期时间(秒)
px,过期时间(毫秒)
nx,如果设置为True,则只有name不存在时,当前set操作才执行
xx,如果设置为True,则只有name存在时,岗前set操作才执行
nx属性是,如果属性不存在,才设置,否则不会设置,如下:
127.0.0.1:6379[1]> set name alex OK 127.0.0.1:6379[1]> set name Alex nx (nil) 127.0.0.1:6379[1]> get name "alex"
上面,我们设置了name属性,接着我们来覆盖这个属性,正常如果没有nx属性,"alex"将被“Alex"值覆盖,但是这里设置了nx,由于name存在,不能覆盖。nx的作用就是如果属性存在,则设置不成功,否则设置成功。
xx只有当属性存在的时候,操作才成功,即只覆盖原来属性,原来属性不存在不会创建新的属性,如下:
127.0.0.1:6379[1]> get name "alex" 127.0.0.1:6379[1]> set name Alex xx OK 127.0.0.1:6379[1]> get name "Alex" 127.0.0.1:6379[1]> set age 22 xx (nil)
从上面程序可以看出,xx是当属性不存在的时候不会设置成功,只有当属性存在了,覆盖原来属性,是用来覆盖原来属性的,属性存在覆盖,不存在不会创建。
setnx(name, value)
设置值,只有name不存在时,执行设置操作(添加)
setex(name, time, value)
# 设置值
# 参数:
# time,过期时间(数字秒 或 timedelta对象)
psetex(key,milliseconds,value)
# 设置值
# 参数:
# time_ms,过期时间(数字毫秒 或 timedelta对象)
mset(*args, **kwargs)
批量设置值 如: mset(k1='v1', k2='v2') 或 mget({'k1': 'v1', 'k2': 'v2'})
批量设置参数,如下:
127.0.0.1:6379[1]> mset k1 v1 k2 v2
OK
127.0.0.1:6379[1]> get k1
"v1"
127.0.0.1:6379[1]> get k2
"v2"
get(name)
获取值
mget(keys, *args)
批量获取 如: mget('ylr', 'wupeiqi') 或 r.mget(['ylr', 'wupeiqi'])
mget(keys,*args)是批量获取值,如下:
127.0.0.1:6379[1]> mget k1 k2
1) "v1"
2) "v2"
getset(name, value)
设置新值并获取原来的值
getset(name,value)是设置并获取原来的新值,如果原来的值不存在,则(nil),如果原来的值存在,获取原来的值,并把新值赋值给原来的属性。如下:
127.0.0.1:6379[1]> getset k1 alex #给k1设置新值,并获取k1原来的值
"v1" #获取到了k1原来的值
127.0.0.1:6379[1]> getset k8 tom
(nil) #属性k8不存在,则获取不到原来的值,但是可以设置k8=tom
127.0.0.1:6379[1]> get k1
"alex" #属性k1的值重新设置了
127.0.0.1:6379[1]> get k8
"tom" #虽然k8不存在,但是可以设置
getrange(key, start, end)
# 获取子序列(根据字节获取,非字符) # 参数: # name,Redis 的 name # start,起始位置(字节) # end,结束位置(字节) # 如: "武沛齐" ,0-3表示 "武"
127.0.0.1:6379> getrange school 0 2
"old"
getrange是获取键值的切片长度,字符长度。中文是以字节形式获取的,在redis里面,都是以字节形式存储的。
127.0.0.1:6379> getrange myname 0 2
"\xe8\x80\xbf"
setrange(name, offset, value)
# 修改字符串内容,从指定字符串索引开始向后替换(新值太长时,则向后添加)
# 参数:
# offset,字符串的索引,字节(一个汉字三个字节)
# value,要设置的值
setrange(name,offset,value)从某个设定的位置开始覆盖,如下:
127.0.0.1:6379> get school
"oldboy"
127.0.0.1:6379> setrange school 2 alex
(integer) 6
127.0.0.1:6379> get school
"olalex"
setrange(name,offset,value)向下偏移offset个字符,覆盖新的值value
setbit(name, offset, value)
# 对name对应值的二进制表示的位进行操作 # 参数: # name,redis的name # offset,位的索引(将值变换成二进制后再进行索引) # value,值只能是 1 或 0 # 注:如果在Redis中有一个对应: n1 = "foo", 那么字符串foo的二进制表示为:01100110 01101111 01101111 所以,如果执行 setbit('n1', 7, 1),则就会将第7位设置为1, 那么最终二进制则变成 01100111 01101111 01101111,即:"goo" # 扩展,转换二进制表示: # source = "武沛齐" source = "foo" for i in source: num = ord(i) print bin(num).replace('b','') 特别的,如果source是汉字 "武沛齐"怎么办? 答:对于utf-8,每一个汉字占 3 个字节,那么 "武沛齐" 则有 9个字节 对于汉字,for循环时候会按照 字节 迭代,那么在迭代时,将每一个字节转换 十进制数,然后再将十进制数转换成二进制 11100110 10101101 10100110 11100110 10110010 10011011 11101001 10111101 10010000 -------------------------- ----------------------------- ----------------------------- 武 沛 齐
bitcount统计列表中1的个数,bitcount,假如要统计一个网站的人数,可以使用数据库来进行统计,可以通过设置不存在的变量来统计网站在线的人数,比如一个人登录,就把这个人的ID设置为1,根据网站注册人的ID编号,即是第几个用户,然后设置一个不存在的属性,如下:
127.0.0.1:6379> setbit n1 1 1 (integer) 0 127.0.0.1:6379> setbit n1 2 1 (integer) 0 127.0.0.1:6379> setbit n1 5 1 (integer) 0 127.0.0.1:6379> bitcount n1 (integer) 3
通过每次用户登录之后,把用户的二进制设置为1,统计1的个数,就能统计人数
上面通过设置,在n1中有三个1存在。
setbit(name,offset,value)是按照二进制形式存在的,10101010001001111010011100011100111111100000
getbit(name, offset)
# 获取name对应的值的二进制表示中的某位的值 (0或1)
127.0.0.1:6379> getbit n1 1
(integer) 1
127.0.0.1:6379> getbit n1 10
(integer) 0
通过获取二进制位的值,1代表登录,0代表未登录。
bitcount(key, start=None, end=None)
# 获取name对应的值的二进制表示中 1 的个数 # 参数: # key,Redis的name # start,位起始位置 # end,位结束位置
bitcount(key,start=None,end=None)统计属性值里面二进制1的个数,比如10100001里面有3个1,bitcount的值就为3.
bitop(operation, dest, *keys)
# 获取多个值,并将值做位运算,将最后的结果保存至新的name对应的值 # 参数: # operation,AND(并) 、 OR(或) 、 NOT(非) 、 XOR(异或) # dest, 新的Redis的name # *keys,要查找的Redis的name # 如: bitop("AND", 'new_name', 'n1', 'n2', 'n3') # 获取Redis中n1,n2,n3对应的值,然后讲所有的值做位运算(求并集),然后将结果保存 new_name 对应的值中
strlen(name)
# 返回name对应值的字节长度(一个汉字3个字节)
127.0.0.1:6379> get school
"olalex\x00\x00\x00\x00tom"
127.0.0.1:6379> strlen school
(integer) 13
获取字节的长度,strlen(name)是获取属性值的字节长度。
incr(self, name, amount=1)
# 自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增。
# 参数:
# name,Redis的name
# amount,自增数(必须是整数)
# 注:同incrby
127.0.0.1:6379> incr n4
(integer) 1
127.0.0.1:6379> incr n4
(integer) 2
127.0.0.1:6379> incr n4
(integer) 3
自增属性,当有新值存在是,自动增加1
incrbyfloat(self, name, amount=1.0)
# 自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增。
# 参数:
# name,Redis的name
# amount,自增数(浮点型)
可以设置定值增加,incr是以1每次递增,incrbyfloat可以以amout=n以任何形式的值自增,如下:
127.0.0.1:6379> incrbyfloat n4 3
"8"
append(key, value)
# 在redis name对应的值后面追加内容
# 参数:
key, redis的name
value, 要追加的字符串
127.0.0.1:6379> get age
"22"
127.0.0.1:6379> append age tom
(integer) 5
127.0.0.1:6379> get age
"22tom"
append(key,value)字符串的拼接,属性拼接值。
Hash操作,redis中Hash在内存中的存储格式如下图:
hash操作其实就是字典的操作,name相当于字典名,hash是字典里面的键值对,如dict={"k1":"v1","k2":"v2"}就是这样的键值对构成,而name属性就是这个字典的名称。
hset(name, key, value)
# name对应的hash中设置一个键值对(不存在,则创建;否则,修改)
# 参数:
# name,redis的name
# key,name对应的hash中的key
# value,name对应的hash中的value
# 注:
# hsetnx(name, key, value),当name对应的hash中不存在当前key时则创建(相当于添加)
hset(name,key,value)其中,name就相当于字典的名,key键,value值,如下:
127.0.0.1:6379> hset info name alex #定义一个字典info,name=alex
(integer) 1
127.0.0.1:6379> hset info age 38 #添加键值对age=38
(integer) 1
hgetall name:获取name属性(字典中)所有键和值
127.0.0.1:6379> hgetall info
1) "name"
2) "alex"
3) "age"
4) "38"
5) "id"
6) "3344"
hget(name,key)
#在name对应的hash中获取根据key获取value
127.0.0.1:6379> hget info name
"alex"
127.0.0.1:6379> hget info age
"38"
hkeys name:查看所有name属性(字典)中的键
127.0.0.1:6379> hkeys info
1) "name"
2) "age"
3) "id"
hvals name:获取所有name属性(字典)中的值 127.0.0.1:6379> hvals info
1) "alex"
2) "38"
3) "3344"
hmset(name, mapping)
# 在name对应的hash中批量设置键值对 # 参数: # name,redis的name # mapping,字典,如:{'k1':'v1', 'k2': 'v2'} # 如: # r.hmset('xx', {'k1':'v1', 'k2': 'v2'})
127.0.0.1:6379> hmset info2 name wupeiqi age 33 id 3636 #批量设置属性键-值
OK
127.0.0.1:6379> hkeys info2
1) "name"
2) "age"
3) "id"
hmget(name, keys, *args)
# 在name对应的hash中获取多个key的值 # 参数: # name,reids对应的name # keys,要获取key集合,如:['k1', 'k2', 'k3'] # *args,要获取的key,如:k1,k2,k3 # 如: # r.mget('xx', ['k1', 'k2']) # 或 # print r.hmget('xx', 'k1', 'k2')
hmget(name,keys,*args)批量获取值,如下:
127.0.0.1:6379> hmget info2 name age id #同时获取info2中的name,age,id键值
1) "wupeiqi"
2) "33"
3) "3636"
hlen(name)
# 获取name对应的hash中键值对的个数
127.0.0.1:6379> hlen info2 #hlen info2获取info2中的键的个数
(integer) 3
hexists(name, key)
# 检查name对应的hash是否存在当前传入的key
,即判断name字典中是否包含Key
127.0.0.1:6379> hexists info2 sex
(integer) 0
127.0.0.1:6379> hexists ifno2 name
(integer) 0
127.0.0.1:6379> hexists info2 age
(integer) 1
hexists(name,key)判断name字典中是否存在键key,存在返回1;不存在,返回0
hdel(name,*keys)
# 将name对应的hash中指定key的键值对删除
127.0.0.1:6379> hvals info2
1) "wupeiqi"
2) "33"
3) "3636"
4) "female"
127.0.0.1:6379> hdel info2 sex #删除info2字典中的sex键值对
(integer) 1
127.0.0.1:6379> hvals info2
1) "wupeiqi"
2) "33"
3) "3636"
hincrby(name, key, amount=1)
# 自增name对应的hash中的指定key的值,不存在则创建key=amount
# 参数:
# name,redis中的name
# key, hash对应的key
# amount,自增数(整数)
HINCRBY key field increment
127.0.0.1:6379> hincrby info2 age 1
(integer) 34
hincrby info2 age 1意思是:info2字典中age键的值增加1,只有整数才能增加,info2中的name是不可以的,会报错,ERR hash value is not an integer,提示hash值不是整数。
hincrbyfloat(name, key, amount=1.0)
# 自增name对应的hash中的指定key的值,不存在则创建key=amount
# 参数:
# name,redis中的name
# key, hash对应的key
# amount,自增数(浮点数)
# 自增name对应的hash中的指定key的值,不存在则创建key=amount
自增函数,与上面一样,只是可以使用浮点数
hscan(name, cursor=0, match=None, count=None)
# 增量式迭代获取,对于数据大的数据非常有用,hscan可以实现分片的获取数据,并非一次性将数据全部获取完,从而放置内存被撑爆 # 参数: # name,redis的name # cursor,游标(基于游标分批取获取数据) # match,匹配指定key,默认None 表示所有的key # count,每次分片最少获取个数,默认None表示采用Redis的默认分片个数 # 如: # 第一次:cursor1, data1 = r.hscan('xx', cursor=0, match=None, count=None) # 第二次:cursor2, data1 = r.hscan('xx', cursor=cursor1, match=None, count=None) # ... # 直到返回值cursor的值为0时,表示数据已经通过分片获取完毕
hscan(name,cursor=0,match=None,count=None)是用来模糊匹配字典中的属性。
127.0.0.1:6379> hscan info3 0 match k* #获取info3中以k开头的键值对
1) "0"
2) 1) "k1"
2) "v1"
3) "k2"
4) "v2"
5) "k3"
6) "v3"
*代表所有,k*代表以*开头。
hscan_iter(name, match=None, count=None)
# 利用yield封装hscan创建生成器,实现分批去redis中获取数据 # 参数: # match,匹配指定key,默认None 表示所有的key # count,每次分片最少获取个数,默认None表示采用Redis的默认分片个数 # 如: # for item in r.hscan_iter('xx'): # print item
List操作,redis中的List在在内存中按照一个name对应一个List来存储。如图:
redis中的列表就是我们常用的列表,只是方式不一样,定义列表名和列表中的值,等价于name=list()
lpush(name,values)
# 在name对应的list中添加元素,每个新的元素都添加到列表的最左边 # 如: # r.lpush('oo', 11,22,33) # 保存顺序为: 33,22,11 # 扩展: # rpush(name, values) 表示从右向左操作
lpush(name,values)就是定义一个名字为name的列表,往里面添加值,如下:
127.0.0.1:6379> lpush names alex geng tom wupeiqi #定义了一个名字为names的列表,并添加alex,geng,tom,wupeiqi四个值到列表中
(integer) 4
lrange name start end:查看列表中起始值,相当于切片,下面查看列表中所有的值:
127.0.0.1:6379> lrange names 0 -1 #查看列表names中所有的值
1) "wupeiqi"
2) "tom"
3) "geng"
4) "alex"
rpush(name,values)
# 在name对应的list中添加元素,每个新的元素都添加到列表的最右边
127.0.0.1:6379> rpush names 1 2 3
(integer) 7
往names列表的右边添加元素
lpushx(name,value)
# 在name对应的list中添加元素,只有name已经存在时,值添加到列表的最左边
# 更多:
# rpushx(name, value) 表示从右向左操作
127.0.0.1:6379> lpushx ages 22 #列表ages不存在,不能插入值
(integer) 0
127.0.0.1:6379> lpushx names cang #列表names存在,可以插入值
(integer)
lpustx(name,value)是向列表中插入值,如果列表存在则插入,如果列表不存在,则不会创建新的列表,不能插入值。
llen(name)
# name对应的list元素的个数
127.0.0.1:6379> llen names
(integer) 8
llen(name)是查看列表的长度,即列表中有几个元素。
linsert(name, where, refvalue, value)
# 在name对应的列表的某一个值前或后插入一个新值 # 参数: # name,redis的name # where,BEFORE或AFTER # refvalue,标杆值,即:在它前后插入数据 # value,要插入的数据
linsert(name,where,refvalue,value),LINSERT key BEFORE|AFTER pivot value在某个值前或值后插入一个值,如下:
127.0.0.1:6379> lrange names 0 -1 1) "cang" 2) "wupeiqi" 3) "tom" 4) "geng" 5) "alex" 6) "6666" 7) "1" 8) "2" 9) "3" 127.0.0.1:6379> linsert names before wupeiqi 666 #在wupeiqi前面插入一个666 (integer) 10 127.0.0.1:6379> linsert names after wupeiqi 6666 #在wupeiqi后面插入一个6666值 (integer) 11 127.0.0.1:6379> lrange names 0 -1 1) "cang" 2) "666" 3) "wupeiqi" 4) "6666" 5) "tom" 6) "geng" 7) "alex" 8) "6666" 9) "1" 10) "2" 11) "3"
linsert()是在指定的值前面或者后面插入一个值。
r.lset(name, index, value)
# 对name对应的list中的某一个索引位置重新赋值
# 参数:
# name,redis的name
# index,list的索引位置
# value,要设置的值
lset(name,index,value)修改列表中某个索引位置的值,现在我们来修改列表names索引为2位置的值,如下:
127.0.0.1:6379> lrange names 0 3 1) "cang" 2) "666" 3) "wupeiqi" 4) "6666" 127.0.0.1:6379> lset names 2 ALEX #修改列表names中索引为2地方的值为ALEX OK 127.0.0.1:6379> lrange names 0 3 1) "cang" 2) "666" 3) "ALEX" 4) "6666"
r.lrem(name, value, num) LREM key count value
# 在name对应的list中删除指定的值 # 参数: # name,redis的name # value,要删除的值 # num, num=0,删除列表中所有的指定值; # num=2,从前到后,删除2个; # num=-2,从后向前,删除2个
lrem key count value删除列表中的值,count是指定删除几个,value是删除的值,key是列表名,如下:
127.0.0.1:6379> lrange names 0 -1 1) "cang" 2) "666" 3) "ALEX" 4) "6666" 5) "tom" 6) "geng" 7) "alex" 8) "6666" 9) "1" 10) "2" 11) "3" 127.0.0.1:6379> lrem names 1 1 #删除列表中的1 (integer) 1 127.0.0.1:6379> lrem names 1 2 #删除列表中的2 (integer) 1 127.0.0.1:6379> lrange names 0 -1 1) "cang" 2) "666" 3) "ALEX" 4) "6666" 5) "tom" 6) "geng" 7) "alex" 8) "6666" 9) "3"
lpop(name) LPOP key
# 在name对应的列表的左侧获取第一个元素并在列表中移除,返回值则是第一个元素
# 更多:
# rpop(name) 表示从右向左操作
lpop(name)删除列表中左边的第一个值,rpop(name)删除列表中右边的第一个值,并返回,如下:
127.0.0.1:6379> lpop names #删除列表names左侧的第一个值,并返回这个值 "cang" 127.0.0.1:6379> rpop names #删除列表names右侧的第一个值,并返回这个值 "3"
lindex(name, index) LINDEX key index
在name对应的列表中根据索引获取列表元素
,即查询列表中第index索引处的值
127.0.0.1:6379> lindex names 1 #查询列表names索引为1处的值
"ALEX"
lrange(name, start, end)
# 在name对应的列表分片获取数据
# 参数:
# name,redis的name
# start,索引的起始位置
# end,索引结束位置
ltrim(name, start, end) LTRIM key start stop
# 在name对应的列表中移除没有在start-end索引之间的值
# 参数:
# name,redis的name
# start,索引的起始位置
# end,索引结束位置
ltrim(name,start,end)移除name列表索引start,end之间以外的所有元素,如下:
127.0.0.1:6379> ltrim names 1 3 #移除names列表中处索引1-3之外所有的元素,只保留1-3之间的元素
OK
127.0.0.1:6379> lrange names 0 -1
1) "ALEX"
2) "6666"
3) "tom"
rpoplpush(src, dst)
# 从一个列表取出最右边的元素,同时将其添加至另一个列表的最左边
# 参数:
# src,要取数据的列表的name
# dst,要添加数据的列表的name
rpoplpush(src,dst)从一个列表右侧拿出一个值,放入另外一个列表的左侧。
blpop(keys, timeout)
# 将多个列表排列,按照从左到右去pop对应列表的元素 # 参数: # keys,redis的name的集合 # timeout,超时时间,当元素所有列表的元素获取完之后,阻塞等待列表内有数据的时间(秒), 0 表示永远阻塞 # 更多: # r.brpop(keys, timeout),从右向左获取数据
brpoplpush(src, dst, timeout=0)
# 从一个列表的右侧移除一个元素并将其添加到另一个列表的左侧 # 参数: # src,取出并要移除元素的列表对应的name # dst,要插入元素的列表对应的name # timeout,当src对应的列表中没有数据时,阻塞等待其有数据的超时时间(秒),0 表示永远阻塞
Set操作,Set集合就是不允许重复的列表
sadd(name,values)
# name对应的集合中添加元素
127.0.0.1:6379> sadd nums 1 2 1 3 4 #创建一个nums集合,并往里面添加值
(integer) 4
smembers(name)
#获取name集合中所有的元素
127.0.0.1:6379> smembers nums #获取集合nums中所有的元素
1) "1"
2) "2"
3) "3"
4) "4"
scard(name)
获取name对应的集合中元素个数
127.0.0.1:6379> scard nums #获取集合nums中元素的个数,集合是无序的,无序集合,所以不能使用切片
(integer) 4
sdiff(keys, *args)
在第一个name对应的集合中且不在其他name对应的集合的元素集合
127.0.0.1:6379> sadd numbers 1 2 3 6 7 9
(integer) 6
127.0.0.1:6379> sdiff nums numbers #获取nums中有的,numbers中没有的元素,即对称差集,nums中有,numbers中没有的元素
1) "4"
sdiffstore(dest, keys, *args)
# 获取第一个name对应的集合中且不在其他name对应的集合,再将其新加入到dest对应的集合中
sinter(keys, *args)
#获取交集
127.0.0.1:6379> sinter numbers nums #获取nums和numbers的交集
1) "1"
2) "2"
3) "3"
sinterstore(dest, keys, *args)
# 获取多一个name对应集合的交集,再讲其加入到dest对应的集合中
127.0.0.1:6379> smembers numbers
1) "1"
2) "2"
3) "3"
4) "6"
5) "7"
6) "9"
sismember(name, value)
# 检查value是否是name对应的集合的成员
smove(src, dst, value)
#将某个成员从一个集合中移动到另外一个集合
spop(name)
# 从集合的右侧(尾部)移除一个成员,并将其返回
srandmember(name, numbers)
# 从name对应的集合中随机获取 numbers 个元素
127.0.0.1:6379> srandmember nums 2 #从集合num2中随机获取两个元素
1) "1"
2) "6"
srem(name, values)
# 在name对应的集合中删除某些值
127.0.0.1:6379> srem nums 6 #删除集合中指定的值
(integer) 1
sunion(keys, *args)
# 获取多一个name对应的集合的并集
sunionstore(dest,keys, *args)
# 获取多一个name对应的集合的并集,并将结果保存到dest对应的集合中
sscan(name, cursor=0, match=None, count=None)
sscan_iter(name, match=None, count=None)
# 同字符串的操作,用于增量迭代分批获取元素,避免内存消耗太大
有序集合,在集合的基础上,为每元素排序;元素的排序需要根据另外一个值来进行比较,所以,对于有序集合,每一个元素有两个值,即:值和分数,分数专门用来做排序。
zadd(name, *args, **kwargs) ZADD key [NX|XX] [CH] [INCR] score member [score member ...]
# 在name对应的有序集合中添加元素 # 如: # zadd('zz', 'n1', 1, 'n2', 2) # 或 # zadd('zz', n1=11, n2=22)
127.0.0.1:6379> zadd people 1 alex 2 wupeiqi #创建有序集合,有序集合名people,分数1,名字alex;分数2,名字wupeiqi
(integer) 2
zrange(name,start,end)
#根据分数高低进行排序
127.0.0.1:6379> zrange people 0 -1 #获取有序集合中的索引元素
1) "alex"
2) "wupeiqi"
在有序集合中,分数可以更改,但是值只有一个。
可以显示分数zrange name start end wihtscores
127.0.0.1:6379> zrange people 0 -1 withscores #显示people有序集合的元素,并显示分数
1) "alex"
2) "1"
3) "wupeiqi"
4) "2"
zcard(name)
# 获取name对应的有序集合元素的数量
127.0.0.1:6379> zcard people #获取有序集合中的元素数量
(integer) 2
zcount(name, min, max)
# 获取name对应的有序集合中分数 在 [min,max] 之间的个数
127.0.0.1:6379> zcount people 1 9 #统计people集合中分数在1-9之间元素的个数
(integer) 4
zincrby(name, value, amount)
# 自增name对应的有序集合的 name 对应的分数
r.zrange( name, start, end, desc=False, withscores=False, score_cast_func=float)
# 按照索引范围获取name对应的有序集合的元素 # 参数: # name,redis的name # start,有序集合索引起始位置(非分数) # end,有序集合索引结束位置(非分数) # desc,排序规则,默认按照分数从小到大排序 # withscores,是否获取元素的分数,默认只获取元素的值 # score_cast_func,对分数进行数据转换的函数 # 更多: # 从大到小排序 # zrevrange(name, start, end, withscores=False, score_cast_func=float) # 按照分数范围获取name对应的有序集合的元素 # zrangebyscore(name, min, max, start=None, num=None, withscores=False, score_cast_func=float) # 从大到小排序 # zrevrangebyscore(name, max, min, start=None, num=None, withscores=False, score_cast_func=float)
zrank(name, value)
获取某个值在 name对应的有序集合中的排行(从 0 开始) # 更多: # zrevrank(name, value),从大到小排序
zrangebylex(name, min, max, start=None, num=None)
# 当有序集合的所有成员都具有相同的分值时,有序集合的元素会根据成员的 值 (lexicographical ordering)来进行排序,而这个命令则可以返回给定的有序集合键 key 中, 元素的值介于 min 和 max 之间的成员 # 对集合中的每个成员进行逐个字节的对比(byte-by-byte compare), 并按照从低到高的顺序, 返回排序后的集合成员。 如果两个字符串有一部分内容是相同的话, 那么命令会认为较长的字符串比较短的字符串要大 # 参数: # name,redis的name # min,左区间(值)。 + 表示正无限; - 表示负无限; ( 表示开区间; [ 则表示闭区间 # min,右区间(值) # start,对结果进行分片处理,索引位置 # num,对结果进行分片处理,索引后面的num个元素 # 如: # ZADD myzset 0 aa 0 ba 0 ca 0 da 0 ea 0 fa 0 ga # r.zrangebylex('myzset', "-", "[ca") 结果为:['aa', 'ba', 'ca'] # 更多: # 从大到小排序 # zrevrangebylex(name, max, min, start=None, num=None)
zrem(name, values)
# 删除name对应的有序集合中值是values的成员 # 如:zrem('zz', ['s1', 's2'])
zremrangebyrank(name, min, max)
#根据排行范围删除
zremrangebyscore(name,min,max)
#根据分数范围删除
zremrangebylex(name,min,max)
#根据值返回删除 zscore(name, value)
#获取name对应有序集合中value对应的分数 zinterstore(dest, keys, aggregate=None)
# 获取两个有序集合的交集,如果遇到相同值不同分数,则按照aggregate进行操作
# aggregate的值为: SUM MIN MAX
zunionstore(dest, keys, aggregate=None)
# 获取两个有序集合的并集,如果遇到相同值不同分数,则按照aggregate进行操作
# aggregate的值为: SUM MIN MAX
zscan(name, cursor=0, match=None, count=None, score_cast_func=float)
zscan_iter(name, match=None, count=None,score_cast_func=float)
# 同字符串相似,相较于字符串新增score_cast_func,用来对分数进行操作
其他常用操作:
delete(*names) ---del name
# 根据删除redis中的任意数据类型
del name删除redis中名字是name的集合,元素的名称,如下:
127.0.0.1:6379> del n4 #删除redis中名称为n4的元素(字符串名称,列表名,字典名,集合名,有序集合名) (integer) 1 127.0.0.1:6379> keys * 1) "numbers" 2) "names" 3) "info2" 4) "number" 5) "myname" 6) "foo" 7) "nums" 8) "info3" 9) "age" 10) "info" 11) "n1" 12) "school" 13) "ifno2"
exists(name)
# 检测redis的name是否存在
127.0.0.1:6379> exists myname #检测redis中是否存在名称为myname的命名
(integer) 1
127.0.0.1:6379> exists tom
(integer) 0
keys(pattern="*")
# 根据模型获取redis的name # 更多: # KEYS * 匹配数据库中所有 key 。 # KEYS h?llo 匹配 hello , hallo 和 hxllo 等。 # KEYS h*llo 匹配 hllo 和 heeeeello 等。 # KEYS h[ae]llo 匹配 hello 和 hallo ,但不匹配 hillo
keys(parrern="*")里面可以加正则表达式,默认是匹配所有,也可以加正则进行匹配
127.0.0.1:6379> keys n* #匹配以n开头的所有命名
1) "numbers"
2) "names"
3) "number"
4) "nums"
5) "n1"
expire(name,time)
# 为某个redis的某个name设置超时时间
rename(src,dst)
# 对redis的name重命名为
修改名字,如下:
127.0.0.1:6379> rename ifno2 info #修改ifno2的名字为info
OK
127.0.0.1:6379> keys *
1) "numbers"
2) "names"
3) "number"
4) "nums"
5) "age"
6) "info"
7) "school"
move(name,db) #redis默认有15个db
# 将redis的某个值移动到指定的db下
randomkey()
# 随机获取一个redis的name(不删除)
127.0.0.1:6379> randomkey #随机获取一个key
"info"
127.0.0.1:6379> randomkey
"name
type(name)
# 获取name对应值的类型
type(name)是查看变量的类型,是字典,集合、字符串等等;如下:
127.0.0.1:6379> type numbers #查看numbers的类型,集合 set 127.0.0.1:6379> type names #查看names的类型,列表 list 127.0.0.1:6379> type info #查看info的类型,hash哈希(即字典) hash 127.0.0.1:6379> type school #查看school的类型,字符串 string
127.0.0.1:6379> type vip #查看vip的类型,有序集合
zset
scan(cursor=0,match=None,count=None)
scan_iter(match=None,count=None)
#同字符串操作,用户增量迭代获取key
4、管道
redis-py默认在执行每次请求都会创建(连接池申请连接)和断开(归还连接池)一次连接操作,如果想要在一次请求中指定多个命令,则可以使用pipline实现一次请求指定多个命令,并且默认情况下一次pipline 是原子性操作.
5、发布订阅
发布者:服务器
订阅者:Dashboad和数据处理(http://www.cnblogs.com/wupeiqi/articles/5132791.html)
Demo如下:
import redis class RedisHelper: def __init__(self): self.__conn = redis.Redis(host='10.211.55.4') self.chan_sub = 'fm104.5' self.chan_pub = 'fm104.5' def public(self, msg): self.__conn.publish(self.chan_pub, msg) return True def subscribe(self): pub = self.__conn.pubsub() pub.subscribe(self.chan_sub) pub.parse_response() return pub
订阅者:
from monitor.RedisHelper import RedisHelper obj = RedisHelper() redis_sub = obj.subscribe() while True: msg= redis_sub.parse_response() print msg
发布者:
from monitor.RedisHelper import RedisHelper obj = RedisHelper() obj.public('hello')