示例:使用流水线优化随机键创建程序
在《数据库》一章的《示例:数据库取样程序》一节中,我们曾经展示过代码清单 13-1 所示的程序,它可以根据用户给定的数量创建多个类型随机的数据库键。
代码清单 13-1 原版的随机键创建程序:/database/create_random_type_keys.py
- import random
- def create_random_type_keys(client, number):
- """
- 在数据库中创建指定数量的类型随机键。
- """
- for i in range(number):
- # 构建键名
- key = "key:{0}".format(i)
- # 从六个键创建函数中随机选择一个
- create_key_func = random.choice([
- create_string,
- create_hash,
- create_list,
- create_set,
- create_zset,
- create_stream
- ])
- # 实际地创建键
- create_key_func(client, key)
- def create_string(client, key):
- client.set(key, "")
- def create_hash(client, key):
- client.hset(key, "", "")
- def create_list(client, key):
- client.rpush(key, "")
- def create_set(client, key):
- client.sadd(key, "")
- def create_zset(client, key):
- client.zadd(key, {"":0})
- def create_stream(client, key):
- client.xadd(key, {"":""})
通过分析代码可知,这个程序每创建一个键,redis-py 客户端就需要与 Redis 服务器进行一次网络通讯:考虑到这个程序执行的都是一些非常简单的命令,每次网络通讯只执行一个命令的做法无疑是非常低效的。为了解决这个问题,我们可以使用流水线把程序生成的所有命令都包裹起来,这样的话,创建多个随机键所需的网络通讯次数就会从原来的 N 次降低为 1 次。代码清单 13-2 展示了修改之后的流水线版本随机键创建程序。
代码清单 13-2 流水线版本的随机键创建程序:/pipeline-and-transaction/create_random_type_keys.py
- import random
- def create_random_type_keys(client, number):
- """
- 在数据库中创建指定数量的类型随机键。
- """
- # 创建流水线对象
- pipe = client.pipeline(transaction=False)
- for i in range(number):
- # 构建键名
- key = "key:{0}".format(i)
- # 从六个键创建函数中随机选择一个
- create_key_func = random.choice([
- create_string,
- create_hash,
- create_list,
- create_set,
- create_zset,
- create_stream
- ])
- # 把待执行的 Redis 命令放入流水线队列中
- create_key_func(pipe, key)
- # 执行流水线包裹的所有命令
- pipe.execute()
- def create_string(client, key):
- client.set(key, "")
- def create_hash(client, key):
- client.hset(key, "", "")
- def create_list(client, key):
- client.rpush(key, "")
- def create_set(client, key):
- client.sadd(key, "")
- def create_zset(client, key):
- client.zadd(key, {"":0})
- def create_stream(client, key):
- client.xadd(key, {"":""})
即使只在本地网络里面进行测试,新版的随机键创建程序也有 5 倍的性能提升。当客户端与服务器处于不同的网络之中,特别是它们之间的连接速度较慢时,流水线版本的性能提升还会更大。