3
0

bitarray.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. # -*- coding: utf-8 -*-
  2. """
  3. Created on 2018/12/14 1:05 PM
  4. ---------
  5. @summary:
  6. ---------
  7. @author: Boris
  8. @email: boris_liu@foxmail.com
  9. """
  10. from __future__ import absolute_import
  11. from feapder.db.redisdb import RedisDB
  12. class BitArray:
  13. def setall(self, value):
  14. pass
  15. def __repr__(self):
  16. raise ImportError("this method mush be implement")
  17. def set(self, offsets, values):
  18. """
  19. 设置字符串数字某一位的值, 返回之前的值
  20. @param offsets: 支持列表或单个值
  21. @param values: 支持列表或单个值
  22. @return: list / 单个值
  23. """
  24. raise ImportError("this method mush be implement")
  25. def get(self, offsets):
  26. """
  27. 取字符串数字某一位的值
  28. @param offsets: 支持列表或单个值
  29. @return: list / 单个值
  30. """
  31. raise ImportError("this method mush be implement")
  32. def count(self, value=True):
  33. raise ImportError("this method mush be implement")
  34. class MemoryBitArray(BitArray):
  35. def __init__(self, num_bits):
  36. try:
  37. import bitarray
  38. except Exception as e:
  39. raise Exception(
  40. "需要安装feapder完整版\ncommand: pip install feapder[all]\n若安装出错,参考:https://boris.org.cn/feapder/#/question/%E5%AE%89%E8%A3%85%E9%97%AE%E9%A2%98"
  41. )
  42. self.num_bits = num_bits
  43. self.bitarray = bitarray.bitarray(num_bits, endian="little")
  44. self.setall(0)
  45. def __repr__(self):
  46. return "MemoryBitArray: {}".format(self.num_bits)
  47. def setall(self, value):
  48. self.bitarray.setall(value)
  49. def set(self, offsets, values):
  50. """
  51. 设置字符串数字某一位的值, 返回之前的值
  52. @param offsets: 支持列表或单个值
  53. @param values: 支持列表或单个值
  54. @return: list / 单个值
  55. """
  56. old_values = []
  57. if isinstance(offsets, list):
  58. if not isinstance(values, list):
  59. values = [values] * len(offsets)
  60. else:
  61. assert len(offsets) == len(values), "offsets值要与values值一一对应"
  62. for offset, value in zip(offsets, values):
  63. old_values.append(int(self.bitarray[offset]))
  64. self.bitarray[offset] = value
  65. else:
  66. old_values = int(self.bitarray[offsets])
  67. self.bitarray[offsets] = values
  68. return old_values
  69. def get(self, offsets):
  70. """
  71. 取字符串数字某一位的值
  72. @param offsets: 支持列表或单个值
  73. @return: list / 单个值
  74. """
  75. if isinstance(offsets, list):
  76. return [self.bitarray[offset] for offset in offsets]
  77. else:
  78. return self.bitarray[offsets]
  79. def count(self, value=True):
  80. return self.bitarray.count(value)
  81. class RedisBitArray(BitArray):
  82. """
  83. 仿bitarray 基于redis
  84. """
  85. redis_db = None
  86. def __init__(self, name, redis_url=None):
  87. self.name = name
  88. self.count_cached_name = name + "_count_cached"
  89. if not self.__class__.redis_db:
  90. self.__class__.redis_db = RedisDB(url=redis_url)
  91. def __repr__(self):
  92. return "RedisBitArray: {}".format(self.name)
  93. def set(self, offsets, values):
  94. """
  95. 设置字符串数字某一位的值, 返回之前的值
  96. @param offsets: 支持列表或单个值
  97. @param values: 支持列表或单个值
  98. @return: list / 单个值
  99. """
  100. return self.redis_db.setbit(self.name, offsets, values)
  101. def get(self, offsets):
  102. return self.redis_db.getbit(self.name, offsets)
  103. def count(self, value=True):
  104. # 先查redis的缓存,若没有 在统计数量
  105. count = self.redis_db.strget(self.count_cached_name)
  106. if count:
  107. return int(count)
  108. else:
  109. count = self.redis_db.bitcount(self.name)
  110. self.redis_db.strset(self.count_cached_name, count, ex=1800) # 半小时过期
  111. return count