2013-06-26 36 views
15

Vấn đề của tôi là phân tích tệp nhật ký và xóa các phần biến trên mỗi dòng để nhóm chúng lại. Ví dụ:Mô-đun trở lại Python trở nên chậm hơn 20 lần khi lặp trên hơn 100 regex khác nhau

s = re.sub(r'(?i)User [_0-9A-z]+ is ', r"User .. is ", s) 
s = re.sub(r'(?i)Message rejected because : (.*?) \(.+\)', r'Message rejected because : \1 (...)', s) 

Tôi có khoảng 120 quy tắc phù hợp như trên.

Tôi đã không tìm thấy vấn đề về hiệu suất trong khi tìm kiếm liên tục trên 100 regex khác nhau. Nhưng một sự chậm lại rất lớn xảy ra khi áp dụng 101 regex.

Các hành vi chính xác tương tự xảy ra khi thay thế các quy định của tôi với

for a in range(100): 
    s = re.sub(r'(?i)caught here'+str(a)+':.+', r'(...)', s) 

Nó đã chậm hơn khi sử dụng phạm vi (101) 20 lần để thay thế.

# range(100) 
% ./dashlog.py file.bz2 
== Took 2.1 seconds. == 

# range(101) 
% ./dashlog.py file.bz2 
== Took 47.6 seconds. == 

Tại sao một điều như vậy lại xảy ra? Và có cách giải quyết nào không?

(Xảy ra trên Python 2.6.6/2.7.2 trên Linux/Windows.)

Trả lời

27

Python giữ bộ nhớ cache nội bộ cho biểu thức chính quy được biên dịch. Bất cứ khi nào bạn sử dụng một trong các hàm mức cao nhất có biểu thức chính quy, Python trước tiên biên dịch biểu thức đó và kết quả của việc biên dịch đó được lưu trữ.

Guess how many items the cache can hold?

>>> import re 
>>> re._MAXCACHE 
100 

Thời điểm bạn vượt quá kích thước bộ nhớ cache, Python 2 xóa tất cả các biểu cache và bắt đầu với một bộ nhớ cache sạch. Python 3 tăng giới hạn lên 512 nhưng vẫn hoàn toàn rõ ràng.

công việc xung quanh là để bạn có thể bộ nhớ cache biên soạn bản thân:

compiled_expression = re.compile(r'(?i)User [_0-9A-z]+ is ') 

compiled_expression.sub(r"User .. is ", s) 

Bạn có thể sử dụng functools.partial() để bó sub() cuộc gọi cùng với các biểu hiện thay thế:

from functools import partial 

compiled_expression = re.compile(r'(?i)User [_0-9A-z]+ is ') 
ready_to_use_sub = partial(compiled_expression.sub, r"User .. is ") 

sau đó sử dụng ready_to_use_sub(s) để sử dụng mẫu biểu thức chính quy được biên dịch cùng với một mẫu thay thế cụ thể.

+0

Ngọt ngào! Đặc biệt vì (có lẽ quá bẩn) 're._MAXCACHE = 200' đang hoạt động hoàn hảo. Tôi sẽ đi cho bộ nhớ cache biên dịch lại của riêng tôi cuối cùng (Và có vẻ như tôi nên đã xem xét mã re.py ngay lập tức). Cảm ơn rất nhiều. – Wiil

+1

Vâng, việc triển khai bộ đệm trong 're' khá nguyên thủy và việc đặt' re._MAXCACHE' sẽ an toàn ngay bây giờ, nếu không phải là ý tưởng hay nhất từ ​​góc độ di động. Nỗ lực để cải thiện câu chuyện bộ nhớ đệm đã được thực hiện, nhưng nỗ lực mới nhất chỉ dẫn đến sự chậm lại, xem [Tại sao không được biên soạn, sử dụng nhiều lần regex chậm hơn nhiều trong Python 3?] (Http://stackoverflow.com/q/14756790) –

Các vấn đề liên quan