2012-09-27 38 views
72

Tôi thực sự ngạc nhiên bởi chức năng của GREP trong shell, trước đây tôi sử dụng phương pháp chuỗi con trong java nhưng bây giờ tôi sử dụng GREP cho nó và nó thực hiện trong vài giây, nó nhanh hơn mã java mà tôi đã từng sử dụng (theo kinh nghiệm của tôi tôi có thể sai mặc dù)Grep chạy quá nhanh như thế nào?

Điều đó đang được nói rằng tôi đã không thể tìm ra cách nó đang xảy ra? cũng không có sẵn trên web.

Có ai có thể giúp tôi với điều này không?

+5

Đây là nguồn mở để bạn có thể tự tìm kiếm. http://www.gnu.org/software/grep/devel.html – driis

+0

@WilliamPursell Khi thời gian thực hiện diễn ra trong vài giây, JIT có thể đã ấm lên và sự khác biệt về trí tuệ là do (1) grep là cực kỳ thông minh về những gì nó làm và (2) mã Java làm cho một lựa chọn thuật toán khá xấu cho vấn đề cụ thể grep tập trung vào. – delnan

+2

Chi tiêu thực hiện Java của bạn mất bao nhiêu thời gian để khởi động JVM và thời gian thực hiện chi tiêu của bạn thực sự mã của bạn là bao nhiêu? Hoặc nó có thể là một vấn đề của thuật toán bạn sử dụng trong mã Java của bạn; một thuật toán O (N^2) có khả năng chậm trong bất kỳ ngôn ngữ nào. –

Trả lời

118

Giả sử câu hỏi của bạn có liên quan đến GNU grep cụ thể. Đây là một lưu ý của tác giả, Mike Haertel:

GNU grep là nhanh vì AVOIDS LOOKING AT EVERY INPUT BYTE.

GNU grep là nhanh vì nó thực hiện các lệnh rất ít CHO MỖI BYTE rằng nó không nhìn vào.

GNU grep sử dụng thuật toán Boyer-Moore nổi tiếng, trông đầu tiên cho chữ cái cuối cùng của chuỗi đích và sử dụng bảng tra cứu để cho biết mức độ vượt xa đầu vào bất cứ khi nào tìm thấy a ký tự không khớp.

GNU grep cũng bỏ vòng lặp bên trong của Boyer-Moore và thiết lập các mục bảng đồng bằng Boyo-Moore theo cách sao cho không cần làm kiểm tra thoát vòng lặp ở mọi bước chưa được kiểm tra. Kết quả của điều này là rằng, trong giới hạn, grep GNU trung bình ít hơn 3 x86 hướng dẫn được thực thi cho mỗi byte đầu vào mà nó thực sự xem xét (và nó bỏ qua hoàn toàn byte).

GNU grep sử dụng các cuộc gọi hệ thống đầu vào Unix thô và tránh sao chép dữ liệu sau khi đọc. Hơn nữa, GNU grep AVOIDS BREAKING INPUT INTO LINES. Tìm kiếm dòng mới sẽ làm chậm grep xuống theo hệ số là nhiều lần, bởi vì để tìm các dòng mới, nó sẽ phải xem xét mỗi byte!

Vì vậy, thay vì sử dụng đầu vào dòng theo định hướng, GNU grep đọc dữ liệu thô thành một bộ đệm lớn, tìm kiếm bộ đệm sử dụng Boyer-Moore, và chỉ khi nó tìm thấy một trận đấu nào nó đi và tìm kiếm các dòng mới bounding (Các tùy chọn dòng lệnh nhất định như -n tắt tối ưu hoá này.)

Câu trả lời này là tập hợp con thông tin được lấy từ here.

27

Để thêm vào câu trả lời tuyệt vời của Steve.

Nó có thể không được biết đến rộng rãi nhưng grep là hầu như luôn luôn nhanh khi grepping cho một còn mẫu dây hơn một ngắn , bởi vì trong một mô hình lâu hơn, Boyer-Moore có thể bỏ qua về phía trước trong những bước tiến dài để đạt được thậm chí tốt hơn sublinear tốc độ:

Ví dụ:

# after running these twice to ensure apples-to-apples comparison 
# (everything is in the buffer cache) 

$ time grep -c 'tg=f_c' 20140910.log 
28 
0.168u 0.068s 0:00.26 

$ time grep -c ' /cc/merchant.json tg=f_c' 20140910.log 
28 
0.100u 0.056s 0:00.17 

Biểu mẫu dài hơn nhanh hơn 35%!

Bằng cách nào? Boyer-Moore bảo vệ một bảng chuyển tiếp từ chuỗi mẫu và bất cứ khi nào có sự không khớp, nó chọn bỏ qua dài nhất có thể (từ lần cuối cùng đến trước) trước khi so sánh một char trong đầu vào với char trong phần bỏ qua bàn.

Dưới đây là a good video explaining Boyer Moore

Một quan niệm sai lầm phổ biến (ví GNU grep) là fgrep nhanh hơn grep. f trong fgrep không phù hợp với 'nhanh', nó là viết tắt của 'cố định' (xem trang người đàn ông), và vì cả hai đều là cùng một chương trình, và cả hai đều sử dụng Boyer-Moore, không có sự khác biệt về tốc độ giữa chúng khi tìm kiếm chuỗi cố định không có ký tự đặc biệt regexp. Lý do duy nhất tôi sử dụng fgrep là khi có một char đặc biệt regexp (như ., [] hoặc *) Tôi không muốn nó được hiểu như vậy. Và thậm chí sau đó, hình thức di động/tiêu chuẩn hơn của grep -F được ưu tiên hơn fgrep.

+2

Trực quan là các mẫu dài hơn sẽ nhanh hơn. Nếu mẫu là một byte thì grep sẽ phải kiểm tra từng byte. Nếu mẫu là 4 byte thì nó có thể làm cho bỏ qua 4 byte. Nếu mô hình được miễn là văn bản thì grep sẽ chỉ thực hiện một bước. – noel

+9

Có, nó là trực quan - nếu bạn hiểu cách thức hoạt động của Boyer-Moore. – arielf

+1

Thậm chí nếu không nó trực quan. Sẽ dễ dàng hơn khi tìm một cây kim dài trong đống cỏ khô hơn một cái kim ngắn hơn – RajatJ

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