You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何优化基于JSON黑名单的域名快速查找性能?

问题描述

我有一个结构如下的JSON黑名单文件:

{
  "urls": [
    "phantomweb.app",
    "aurory.app",
    "solvision.io",
    "staratlas.art",
    "starsatlas.com",
    "sollet.cc",
    "raydlum.io",
    "aurorynft.com",
    "solletweb.io",
    "fancyfrenchienft.art",
    "solanawebwallet.online"
  ]
}

我需要用这个文件做域名黑名单快速查询,当前实现代码如下:

def fast_list_lookup(lst, search):
    from bisect import bisect_left

    return (search <= lst[-1]) and (lst[bisect_left(lst, search)] == search)


def check_domain_blocklist(url, blocklist_path="/tmp/blocklist.json"):
    import urlparse

    with io.open(blocklist_path) as fh:
        data = json.load(fh)["urls"]
        data.sort()
        parsed_domain = urlparse.urlparse(url).netloc
        return fast_list_lookup(data, parsed_domain)

当前性能测试结果:

for _ in {1..5}; do time python test.py; done

real    0m3.228s
user    0m0.511s
sys     0m0.296s

real    0m3.778s
user    0m0.504s
sys     0m0.530s

real    0m4.048s
user    0m0.594s
sys     0m0.537s

real    0m4.131s
user    0m0.761s
sys     0m0.386s

real    0m4.204s
user    0m0.700s
sys     0m0.488s

希望通过优化文件加载或列表排序环节,把整体耗时缩减1-2秒,求可行的优化方案。

优化方案

1. 提前预加载并缓存黑名单数据

当前代码每次调用查询函数都会重复加载JSON文件、重新排序,这是性能损耗的核心原因。把数据加载和排序逻辑移到函数外部,程序启动时只执行一次:

import json
import io
import urlparse
from bisect import bisect_left

# 程序启动时一次性加载并排序黑名单
with io.open("/tmp/blocklist.json") as fh:
    BLOCKLIST = sorted(json.load(fh)["urls"])

def fast_list_lookup(lst, search):
    return (search <= lst[-1]) and (lst[bisect_left(lst, search)] == search)

def check_domain_blocklist(url):
    parsed_domain = urlparse.urlparse(url).netloc
    return fast_list_lookup(BLOCKLIST, parsed_domain)

这样每次查询时无需重复读文件和排序,直接复用预处理好的列表,能大幅降低IO和计算开销。

2. 改用集合实现O(1)复杂度查询

列表二分查找是O(logN)复杂度,而集合的成员查询是O(1),更适合黑名单查询场景。同样提前加载并转为集合:

import json
import io
import urlparse

# 提前加载并转为集合
with io.open("/tmp/blocklist.json") as fh:
    BLOCKLIST_SET = set(json.load(fh)["urls"])

def check_domain_blocklist(url):
    parsed_domain = urlparse.urlparse(url).netloc
    return parsed_domain in BLOCKLIST_SET

这个改动彻底消除了排序开销,同时把查询速度提到最快。

3. 优化文件存储与加载方式

如果黑名单文件较大,可进一步优化加载效率:

  • 将JSON文件转为纯文本格式(每行一个域名),加载时直接读取所有行,比解析JSON更快:
    # 假设黑名单为每行一个域名的txt文件
    with io.open("/tmp/blocklist.txt") as fh:
        BLOCKLIST_SET = set(line.strip() for line in fh if line.strip())
    
  • 若必须保留JSON格式,可提前将排序后的列表或集合序列化(如用pickle),后续直接加载序列化文件,避免重复解析JSON和排序:
    # 第一次运行时序列化缓存
    import pickle
    with io.open("/tmp/blocklist.json") as fh:
        data = sorted(json.load(fh)["urls"])
    with open("/tmp/blocklist_cache.pkl", "wb") as f:
        pickle.dump(data, f)
    
    # 后续直接加载缓存文件
    with open("/tmp/blocklist_cache.pkl", "rb") as f:
        BLOCKLIST = pickle.load(f)
    

4. 调整导入语句位置

当前代码在函数内部导入urlparse和bisect_left,每次调用都会触发导入检查,虽开销不大,但移到函数外部可避免重复操作,小幅提升性能。

内容的提问来源于stack exchange,提问作者user12969777

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 10:15:12