代码之家  ›  专栏  ›  技术社区  ›  xendi

Cerberus/regex瓶颈-性能验证实践

  •  0
  • xendi  · 技术社区  · 5 年前

    我在用AIOHTTP做网络应用。我正在使用Cerberus验证用户输入。我使用wrk基准测试工具运行了一些测试,发现以下Cerberus验证器:

    "uri": {
            "type": "string",
            "coerce": str,
            "required": True,
            "minlength": 1,
            "maxlength": 255,
            "regex": "^[a-zA-Z0-9/_]+$"
        }
    

    为网页增加大约10-15%的加载时间。这对我来说是无法接受的。如何解决这个问题?只是正则表达式引擎吗?有没有比这更快的模块?我知道字符串解析函数通常比regex快。有没有不使用regex的验证引擎?一个将regex转换为字符串解析的工具会很有趣。

    编辑:我运行了一个探查器:

    from cerberus import Validator
    from speed_profiler import SpeedProfiler
    from pprint import pprint
    
    def referer_validator(value):
        if len(value) < 1 or len(value) > 256:
            return False
        if not any(not l.isalnum() and l not in ['_', '/'] for l in value):
            return False
        return True
    
    
    v = Validator()
    v.schema = {
        "path": {
            "type": "string",
            "coerce": str,
            "required": True,
            "minlength": 1,
            "maxlength": 255,
            "regex": "^[a-zA-Z0-9/_]+$"
        }
    }
    
    sp = SpeedProfiler('Cerberus')
    
    v.validate({'path': '/some/path_foo'})
    
    sp.mark('Parser Function')
    
    referer_validator('/some/path_foo')
    
    profile = sp.stop()
    pprint(profile)
    

    这证实了Cerberus很慢:

    [{'duration': 0.00029901403468102217,
      'identifier': 'Cerberus',
      'line_num': 27,
      'percent_time': 98.26},
     {'duration': 5.29497629031539e-06,
      'identifier': 'Parser Function',
      'line_num': 31,
      'percent_time': 1.74}]
    

    这证实了Cerberus是慢的。现在,我用这个来提高速度:

    def path_valid(value):
        if len(value) < 1 or len(value) > 256:
            return False
        if not any(not l.isalnum() and l not in ['_', '/'] for l in value):
            return False
        return True
    
    0 回复  |  直到 5 年前
        1
  •  0
  •   Wiktor Stribiżew    5 年前

    如果您喜欢使用非正则表达式解决方案,您可以使用

    def path_valid(value):
        if len(value) < 1 or len(value) > 255:
            return False
        if not any(not l.isalnum() and l not in ['_', '/'] for l in value):
            return False
        return True
    

    如果值的长度小于1或大于255(由于 if len(value) < 1 or len(value) > 255 如果有一个字符不是字母数字的,也不是 _ / if not any(not l.isalnum() and l not in ['_', '/'] for l in value) ).

    Python test here .