2012-03-28 21 views
6

Tôi hiện đang viết một tập lệnh Python để xử lý khoảng 10.000 tài liệu đầu vào. Dựa trên đầu ra tiến độ của tập lệnh, tôi nhận thấy rằng 400 tài liệu đầu tiên được xử lý rất nhanh và sau đó tập lệnh chậm lại mặc dù các tài liệu đầu vào đều có cùng kích thước.Cách Pythonic và hiệu quả để xác định nhiều regex để sử dụng trong nhiều lần lặp

Tôi giả định điều này có thể liên quan đến thực tế rằng hầu hết quá trình xử lý tài liệu được thực hiện với các regex mà tôi không lưu dưới dạng đối tượng regex khi chúng đã được biên dịch. Thay vào đó, tôi biên dịch lại các regex bất cứ khi nào tôi cần chúng.

Vì kịch bản của tôi có khoảng 10 hàm khác nhau, tất cả đều sử dụng khoảng 10 - 20 mẫu regex khác nhau, tôi tự hỏi điều gì sẽ hiệu quả hơn trong Python để tránh biên dịch lại các mẫu regex lặp đi lặp lại (trong Perl Tôi chỉ có thể bao gồm một sửa đổi //o).

giả định của tôi là nếu tôi lưu trữ các đối tượng regex trong các chức năng cá nhân sử dụng

pattern = re.compile() 

kết quả đối tượng regex sẽ không được giữ lại cho đến khi gọi tiếp theo của chức năng cho phiên bản kế tiếp (mỗi hàm được gọi nhưng một lần cho mỗi tài liệu).

Tạo danh sách toàn cầu các regex được biên dịch trước có vẻ là một tùy chọn không hấp dẫn vì tôi cần lưu trữ danh sách các regex ở một vị trí khác trong mã của tôi so với nơi chúng thực sự được sử dụng.

Mọi lời khuyên ở đây về cách xử lý gọn gàng và hiệu quả?

+2

Không, nó phải làm với thực tế là * bộ nhớ cache của bạn bị cạn kiệt *. –

+1

Bạn đã lược tả mã của mình chưa? – Daenyth

+1

là tất cả các chức năng được áp dụng cho tất cả các tài liệu? bởi vì nếu như vậy, @larsmans trả lời, trong khi tốt, dường như không giải thích sự chậm lại sau 400 tài liệu. tôi sẽ đề nghị lược tả hơn là đoán ... –

Trả lời

9

Mô-đun lưu trữ lại được biên dịch các mẫu regex. Bộ nhớ cache bị xóa khi nó đạt đến kích thước của re._MAXCACHE theo mặc định là 100. (Vì bạn có 10 hàm với 10-20 regexes mỗi (tức là 100-200 regex), mức quan sát của bạn giảm xuống có ý nghĩa với việc xóa . bộ nhớ cache)

Nếu bạn là okay với thay đổi biến riêng, sửa chữa nhanh chóng và dơ bẩn để chương trình của bạn có thể là để thiết lập re._MAXCACHE đến một giá trị cao hơn:

import re 
re._MAXCACHE = 1000 
+0

Điều này thật thú vị .... cảm ơn cho gợi ý này. – Pat

2

Biểu thức chính quy được biên dịch tự động được lưu trữ theo re.compile, re.searchre.match, nhưng kích thước bộ nhớ cache tối đa là 100 trong Python 2.7, vì vậy bạn đang tràn bộ nhớ cache.

Tạo danh sách toàn cầu các regex được biên dịch trước có vẻ không hấp dẫn vì tôi cần lưu trữ danh sách regex ở vị trí khác trong mã của tôi so với nơi chúng thực sự được sử dụng.

Bạn có thể xác định chúng gần nơi chúng được sử dụng: ngay trước các chức năng sử dụng chúng. Nếu bạn sử dụng lại cùng một RE ở một vị trí khác, thì tốt hơn hết nên định nghĩa nó trên toàn cầu để tránh phải sửa đổi nó ở nhiều nơi.

5

thời gian qua tôi nhìn, re.compile duy trì một bộ nhớ cache khá nhỏ, và khi nó đầy, chỉ cần làm trống nó.Tự làm không có giới hạn:

class MyRECache(object): 
    def __init__(self): 
     self.cache = {} 
    def compile(self, regex_string): 
     if regex_string not in self.cache: 
      self.cache[regex_string] = re.compile(regex_string) 
     return self.cache[regex_string] 
+5

Hoặc, thậm chí ngắn gọn hơn, [xuất phát từ 'dict' và ghi đè lên' __missing__() '] (https://gist.github.com/2230130). –

+1

@SvenMarnach: Mã mà tôi viết có thể được hiểu bởi người mà không cần tra cứu tài liệu '__voodoo__'. –

+0

Sẽ rất thú vị khi biết bộ nhớ cache bị xóa khi dung lượng của nó được sử dụng hết ... tất cả các mục đã bị xóa hay chỉ một vài? – Pat

1

Với tinh thần "đơn giản là tốt hơn" Tôi muốn sử dụng một hàm helper ít như thế này:

def rc(pattern, flags=0): 
    key = pattern, flags 
    if key not in rc.cache: 
     rc.cache[key] = re.compile(pattern, flags) 
    return rc.cache[key] 

rc.cache = {} 

Cách sử dụng:

rc('[a-z]').sub... 
rc('[a-z]').findall <- no compilation here 

Tôi cũng khuyên bạn nên thử regex. Trong số rất nhiều lợi thế khác so với tái chứng khoán, MAXCACHE của nó là 500 theo mặc định và sẽ không bị rơi hoàn toàn do tràn.

+0

Xin cảm ơn tất cả những ai bận tâm trả lời truy vấn của tôi. Tôi sẽ theo dõi trên nhiều con trỏ hữu ích. Hỗ trợ của bạn được nhiều đánh giá cao!. – Pat

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