示例:使用流水线优化随机键创建程序

在《数据库》一章的《示例:数据库取样程序》一节中,我们曾经展示过代码清单 13-1 所示的程序,它可以根据用户给定的数量创建多个类型随机的数据库键。


代码清单 13-1 原版的随机键创建程序:/database/create_random_type_keys.py

  1. import random
  2.  
  3. def create_random_type_keys(client, number):
  4. """
  5. 在数据库中创建指定数量的类型随机键。
  6. """
  7. for i in range(number):
  8. # 构建键名
  9. key = "key:{0}".format(i)
  10. # 从六个键创建函数中随机选择一个
  11. create_key_func = random.choice([
  12. create_string,
  13. create_hash,
  14. create_list,
  15. create_set,
  16. create_zset,
  17. create_stream
  18. ])
  19. # 实际地创建键
  20. create_key_func(client, key)
  21.  
  22. def create_string(client, key):
  23. client.set(key, "")
  24.  
  25. def create_hash(client, key):
  26. client.hset(key, "", "")
  27.  
  28. def create_list(client, key):
  29. client.rpush(key, "")
  30.  
  31. def create_set(client, key):
  32. client.sadd(key, "")
  33.  
  34. def create_zset(client, key):
  35. client.zadd(key, {"":0})
  36.  
  37. def create_stream(client, key):
  38. client.xadd(key, {"":""})

通过分析代码可知,这个程序每创建一个键,redis-py 客户端就需要与 Redis 服务器进行一次网络通讯:考虑到这个程序执行的都是一些非常简单的命令,每次网络通讯只执行一个命令的做法无疑是非常低效的。为了解决这个问题,我们可以使用流水线把程序生成的所有命令都包裹起来,这样的话,创建多个随机键所需的网络通讯次数就会从原来的 N 次降低为 1 次。代码清单 13-2 展示了修改之后的流水线版本随机键创建程序。


代码清单 13-2 流水线版本的随机键创建程序:/pipeline-and-transaction/create_random_type_keys.py

  1. import random
  2.  
  3. def create_random_type_keys(client, number):
  4. """
  5. 在数据库中创建指定数量的类型随机键。
  6. """
  7. # 创建流水线对象
  8. pipe = client.pipeline(transaction=False)
  9. for i in range(number):
  10. # 构建键名
  11. key = "key:{0}".format(i)
  12. # 从六个键创建函数中随机选择一个
  13. create_key_func = random.choice([
  14. create_string,
  15. create_hash,
  16. create_list,
  17. create_set,
  18. create_zset,
  19. create_stream
  20. ])
  21. # 把待执行的 Redis 命令放入流水线队列中
  22. create_key_func(pipe, key)
  23. # 执行流水线包裹的所有命令
  24. pipe.execute()
  25.  
  26. def create_string(client, key):
  27. client.set(key, "")
  28.  
  29. def create_hash(client, key):
  30. client.hset(key, "", "")
  31.  
  32. def create_list(client, key):
  33. client.rpush(key, "")
  34.  
  35. def create_set(client, key):
  36. client.sadd(key, "")
  37.  
  38. def create_zset(client, key):
  39. client.zadd(key, {"":0})
  40.  
  41. def create_stream(client, key):
  42. client.xadd(key, {"":""})

即使只在本地网络里面进行测试,新版的随机键创建程序也有 5 倍的性能提升。当客户端与服务器处于不同的网络之中,特别是它们之间的连接速度较慢时,流水线版本的性能提升还会更大。