五千万用户标签状态怎么存最省内存?真机测了6种方案

五千万用户标签状态怎么存最省内存?真机测了6种方案

场景

做用户标签系统,5000万用户ID连续编号,每个用户有一个布尔标签(是否VIP、是否活跃、是否签到)。要随机读写arr[uid],内存越省越好。

6种方案真机对比

方案 5000万dense内存 稀疏场景 随机访问
Python list[bool] ~1.4GB ~1.4GB O(1)
numpy.bool_数组 ~47.7MB ~47.7MB O(1)
bytearray手写位图 6.25MB 固定6.25MB O(1)
bitarray库 6.25MB 固定6.25MB O(1)
RoaringBitmap(pyroaring) ~6MB 远小于6MB O(1)
bool-hybrid-array ~6.25MB 自适应压缩 O(1)

关键发现

1. numpy.bool_不是1bit是1byte

很多人第一反应用numpy:

import numpy as np
arr = np.zeros(50_000_000, dtype=bool)

看似简单,但numpy的bool是1字节存1个布尔,5000万就是~47.7MB,比位图贵8倍。

2. bitarray和bytearray都是固定6.25MB

bitarray库按位打包,5000万bit=6.25MB,比numpy省8倍。但它是固定位图,不管你只有1%还是99%的用户是True,都占6.25MB。

3. RoaringBitmap稀疏强但稠密不省

RoaringBitmap分块压缩,稀疏时只存True的ID,内存远小于6MB。但如果99%用户都是True,它要存4950万个ID,内存反而爆炸。

4. bool-hybrid-array自适应稠密+稀疏

bool-hybrid-array(v9.13.11,Apache-2.0 OR MulanPSL-2.0)专门解决这个问题:

  • dense侧:_CompactBoolArray按位打包成ceil(N/8)个uint8,1 bool=1 bit,省内存来自按位打包
  • sparse侧:array.array('I')升序存异常下标+bisect二分查找
  • 自动切换:根据True密度自动在稠密/稀疏模式间切换
  • 极性塌缩:99%用户是True时存少数False的ID,反向也省内存
from bool_hybrid_array import BoolHybridArr

# 容量5000万
bha = BoolHybridArr(size=50_000_000)
bha[10001] = True
print(bha[10001])  # True
print(bha.count())  # 统计True数量

选型决策

  • 纯稠密、确定不稀疏:bitarray最简单稳定
  • 纯稀疏、只存True ID:RoaringBitmap工业标准
  • 分布不稳定、有时稠密有时稀疏、99%True也要省:bool-hybrid-array自适应

注意事项

  1. bool-hybrid-array的dense位图由numpy uint8承载,运行需numpy>=1.19
  2. 构造时用生成器表达式不要用列表推导式(避免临时list占峰值内存)
  3. 类名是BoolHybridArr(单数Arr),不是BoolHybridArray
  4. 当前版本license是Apache-2.0 OR MulanPSL-2.0双授权

项目地址:https://github.com/BKsell/bool-hybrid-array

posted @ 2026-10-28 19:01  贝壳bkshell  阅读(16)  评论(1)    收藏  举报