Узкие места в Cerberus / regex - Практические методы проверки - PullRequest
0 голосов
/ 09 марта 2020

Я использую AIOHTTP для веб-приложения. Я использую Цербер для проверки ввода пользователя. Я провел несколько тестов с помощью wrk benchmark tool и обнаружил, что следующий валидатор Cerberus:

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

добавляет около 10-15% времени загрузки веб-страниц. Это граница для меня неприемлема. Как подойти к этой проблеме? Это просто движок регулярных выражений? Известно ли, что модуль работает быстрее? Я знаю, что функции разбора строк обычно быстрее, чем регулярные выражения. Есть ли механизм проверки, который не использует регулярные выражения? Интересно было бы использовать инструмент для преобразования регулярных выражений в синтаксический анализ строки.

Редактировать: я запустил профилировщик:

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)

, который подтверждает, что Цербер медленный:

[{'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}]

Это подтверждает, что Цербер медленный. Сейчас я использую это для лучшей скорости:

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

1 Ответ

0 голосов
/ 10 марта 2020

Если вы предпочитаете использовать решение без регулярных выражений, вы можете использовать

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 проверка) и сбой произойдет, если есть символ, который не является alphanumeri c и не _ или / (проверка сделана с помощью if not any(not l.isalnum() and l not in ['_', '/'] for l in value)).

См. Python тест здесь .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...