python / python/cpython

Improve performance of `re.compile()` for patterns with character ranges

Abierto
#149,427 0 comentarios 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

performance stdlib topic-regex type-feature
Lenguaje dominante
Python
Estrellas
77.2k
Forks
35.9k
Métricas de merge de PR
Métricas de PR pendientes

Descripción

Feature or enhancement

Proposal:

re._compiler._optimize_charset builds a 256-byte (or wider) charmap for character classes. On main it is filled with a loop:

for i in range(av[0], av[1] + 1):
    charmap[i] = 1

Replacing the loop with a single bytearray slice is faster.

Benchmark results on pyperformance regex_compile

main (86.2 ± 1.4 ms)  ->  PR (78.5 ± 1.6 ms):  1.10x faster

Microbenchmarks:

compile-charsets-small:  2.80 ± 0.04 ms  ->  1.22 ± 0.02 ms:  2.29x faster
compile-charsets-big:    1.46 ± 0.03 ms  ->  1.36 ± 0.03 ms:  1.08x faster
Geometric mean:                                              1.57x faster

The "small" case oversamples wide ranges ([\x00-\xff], BMP range) which benefit most. The "big" case has mostly small ASCII ranges where the slice-fill construction (b'\x01' * n) competes with the loop savings.

microbench script
"""Microbench for the bytearray slice-fill optimization in
re._compiler._optimize_charset (RANGE handler)."""
import pyperf
import re

SMALL_PATTERNS = [
    r'[a-zA-Z0-9_]+',
    r'[^\s\d]+',
    r'[a-z][A-Z][0-9]',
    r'[\x00-\xff]',                  # full byte range
    r'[Ā-῿]+',                       # BMP range, hits growth path
    r'[a-zA-Z0-9!@#$%^&*()_+\-=\[\]{};:\'",.<>/?\\|`~]+',
    r'[0-9a-fA-F]{2,8}',
    r'[ -~]+',                       # all printable ASCII
]

BIG_PATTERN = (
    r'^([a-zA-Z][a-zA-Z0-9_\-]*)\s*'
    r'([\x20-\x7e]*)\s*'
    r'([-ÿĀ-ɏ]+)?\s*'
    r'([0-9]{1,4}[\-/.][0-9]{1,2}[\-/.][0-9]{1,4})?\s*'
    r'([^\s,;:]+)$'
)

def compile_small():
    for _ in range(8):
        for p in SMALL_PATTERNS:
            re.purge()
            re.compile(p)

def compile_big():
    for _ in range(10):
        re.purge()
        re.compile(BIG_PATTERN)

runner = pyperf.Runner()
runner.bench_func('compile-charsets-small', compile_small)
runner.bench_func('compile-charsets-big', compile_big)
Has this already been discussed elsewhere?

No response given

Links to previous discussion of this feature:

No response

Linked PRs
  • gh-149428

Guía de contribución

Abrir la guía de contribución

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Línea de trabajo

Comienza en re._compiler._optimize_charset, centrándote en el manejador RANGE que rellena charmap. Revisa el PR vinculado gh-149428 y compara su comportamiento para rangos de caracteres pequeños y amplios. Se considera terminado cuando el manejo de rangos siga siendo correcto y regex_compile y los microbenchmarks proporcionados reproduzcan la mejora de rendimiento prevista.

Escrito por el modelo de indexación a partir del texto del issue.

Evaluación

Stack tecnológico
python
Área
performance
Tipo de issue
Nueva funcionalidad
Dificultad
2/5
Tiempo estimado
1-3 horas
Estado de actividad
Estancado
Claridad
Bien especificado
Aptitud para principiantes
25/100

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.