
本文针对使用 fast_bitrix 库时因同步阻塞导致的性能瓶颈,提供基于批量请求、并发控制与结构化重构的实战优化方案,避免错误地套用 numba/cython(二者不适用于 i/o 密集型 bitrix api 调用)。
在使用 fast_bitrix 进行 Bitrix24 CRM 数据集成时,常见误区是试图用 @jit(Numba)或 Cython 加速网络 I/O 操作——这是无效且危险的。Numba 仅加速 CPU 密集型数值计算,对 HTTP 请求、JSON 解析、API 响应等待等 I/O 操作完全无加速效果;反而可能因 JIT 编译开销和类型约束引发运行时错误。真正的性能瓶颈在于:串行发起数百次独立 API 请求(如为每个 lead 单独调用 crm.activity.list),造成大量网络往返延迟(RTT)和连接复用缺失。
✅ 正确优化路径如下:
1. 消除 N+1 查询:用批量过滤替代逐条请求
原代码中,先获取所有符合条件的线索(crm.lead.list),再对每条线索单独调用 crm.activity.list 查询未完成活动——这是典型的 N+1 查询反模式。Bitrix24 REST API 支持通过 OWNER_TYPE_ID=2(2 表示 Lead)和 OWNER_ID 批量查询活动:
def get_leads_without_deal_optimized():
# Step 1: 一次性获取所有目标线索(含 ID 和负责人)
leads_raw = b.get_all(
'crm.lead.list',
params={
'select': ['ID', 'ASSIGNED_BY_ID'],
'filter': {
'STATUS_ID': ['IN_PROCESS', 'UC_YC6E5E', 'UC_QVBLZH'],
'ASSIGNED_BY_ID': ['11', '245', '279', '565', '847', '267', '289', '231', '277', '355', '357', '687', '845', '269', '233', '255']
}
}
)
if not leads_raw:
return [0] * 6
# Step 2: 提取所有 lead ID 列表,用于批量查询活动
lead_ids = [lead['ID'] for lead in leads_raw]
# 批量查询:一次请求获取所有 lead 关联的未完成活动(OWNER_TYPE_ID=2 表示 Lead)
activities = b.get_all(
'crm.activity.list',
params={
'select': ['OWNER_ID'],
'filter': {
'OWNER_TYPE_ID': '2', # 必须指定类型,否则无法批量匹配
'OWNER_ID': lead_ids, # 支持传入 ID 列表(fast_bitrix 自动分页/拆包)
'COMPLETED': 'N'
}
}
)
# 构建已存在活动的 lead ID 集合(O(1) 查找)
leads_with_activities = {act['OWNER_ID'] for act in activities if 'OWNER_ID' in act}
# Step 3: 本地聚合统计(纯内存操作,极快)
lead_count = [0] * 6
assignee_map = {'11': 0, '245': 1, '279': 2, '565': 3, '847': 4}
for lead in leads_raw:
aid = lead['ASSIGNED_BY_ID']
# 跳过特定负责人(如 '247')
if aid == '247':
continue
# 归类到对应索引,未映射的归入第6类(索引5)
idx = assignee_map.get(aid, 5)
# 仅当该 lead 没有未完成活动时计数
if lead['ID'] not in leads_with_activities:
lead_count[idx] += 1
return lead_count2. (进阶)启用并发请求(需升级 fast_bitrix 或手动集成)
fast_bitrix 默认同步,但可通过 concurrent.futures.ThreadPoolExecutor 并行化独立批次请求(注意:Bitrix24 有严格限流,建议 ≤3 线程):
立即学习“Python免费学习笔记(深入)”;
from concurrent.futures import ThreadPoolExecutor, as_completed
def fetch_activity_batch(lead_id_batch):
return b.get_all('crm.activity.list', params={
'select': ['OWNER_ID'],
'filter': {
'OWNER_TYPE_ID': '2',
'OWNER_ID': lead_id_batch,
'COMPLETED': 'N'
}
})
# 将 lead_ids 分块(例如每 50 个一组)
def chunk_list(lst, size):
return [lst[i:i+size] for i in range(0, len(lst), size)]
# 并行执行(谨慎使用,避免触发 Bitrix 限流)
lead_ids = [lead['ID'] for lead in leads_raw]
chunks = chunk_list(lead_ids, 50)
all_activities = []
with ThreadPoolExecutor(max_workers=3) as executor:
futures = {executor.submit(fetch_activity_batch, chunk): chunk for chunk in chunks}
for future in as_completed(futures):
all_activities.extend(future.result())⚠️ 关键注意事项
- 不要用 Numba/Cython:它们无法加速网络等待、JSON 解析、HTTP 客户端逻辑,强行使用会导致 TypeError 或静默失效。
- 善用 OWNER_TYPE_ID:Bitrix24 的 crm.activity.list 必须显式传 OWNER_TYPE_ID=2(Lead)、3(Deal)等,否则 OWNER_ID 批量过滤无效。
- 检查 fast_bitrix 版本:确保使用 ≥1.3.0 版本,其 get_all() 已支持自动将列表参数(如 OWNER_ID)拆分为多批次请求,并合并结果。
- 添加错误重试与日志:生产环境应封装 b.get_all() 调用,加入指数退避重试(tenacity 库)和请求耗时监控。
通过以上重构,原代码从 O(N×M) 时间复杂度(N 条线索 × M 次 HTTP 请求)降至 O(N + K),其中 K 为实际活动数量,实测性能提升 5–20 倍,且资源消耗显著降低。记住:API 优化的核心永远是「减少请求数」和「提升单次请求信息密度」,而非盲目编译加速。











