Có cách nào để làm cho lớp lót này nhanh hơn không?


7

Bối cảnh

Tôi có một thư mục gồm hàng ngàn tệp zip được ghi ngày tháng trong mẫu YYYYMMDD_hhmmss.zipvà mỗi tệp khoảng 300K. Trong mỗi tệp zip có khoảng 400 tệp xml, mỗi tệp khoảng 3K.

Vấn đề

Tôi cần có thể tìm kiếm và tìm một chuỗi nhất định trong phạm vi ngày của các tệp zip.

Giải pháp hiện tại (mặc dù tầm thường)

Tôi có một lớp lót sau đây

find /home/mydir/ -type f | sort | \
awk "/xml_20140207_000016.zip/,/xml_20140207_235938.zip/" | \
xargs -n 1 -P 10 zipgrep "my search string"

Quan điểm của nó là

  1. liệt kê tất cả các tập tin trong thư mục nghìn tập tin của tôi
  2. sắp xếp danh sách các tập tin
  3. lấy một phạm vi tệp dựa trên ngày đã cho ( awklệnh này chỉ in các dòng sau chuỗi khớp đầu tiên đó và tối đa chuỗi khớp thứ hai đó)
  4. chuyển từng dòng kết quả tương ứng với một tệp zipgrep

Câu hỏi

Lớp lót này chạy chậm khủng khiếp, thậm chí với 10 quy trình trên máy 24 lõi. Tôi tin rằng nó chậm vì zipgreplệnh nhưng tôi không đủ khôn ngoan để biết cách cải thiện nó. Tôi không biết mình có nên không, nhưng tôi hơi xấu hổ khi một đồng nghiệp đã viết một công cụ java chạy nhanh hơn kịch bản này. Tôi muốn đảo ngược điều đó nếu có thể. Sau đó, có ai biết làm thế nào để thực hiện lệnh này nhanh hơn trong bối cảnh này? Hoặc để cải thiện bất kỳ phần nào của nó?


1
Bạn có chắc chắn phạm vi năm chỉ đến năm 999? không phải là nó thay đổi câu hỏi nhiều
Anthon

4
zipgrep riêng biệt giải nén mọi tệp trong zipfile để grep nó, điều đó dường như không hiệu quả nếu bạn vẫn đang xem tất cả chúng. Có thể giải nén int một thư mục tạm thời và grepping ở đó hoặc loay hoay với đầu ra của unzip -phoặc unzip -csẽ cải thiện một chút.
Ulrich Schwarz

@UlrichSchwarz Tôi không biết về điều đó, tôi sẽ thử nó. Cảm ơn!
fifosine

Làm thế nào cao là khả năng của chuỗi xảy ra? Mở rộng theo đề xuất trước đây của tôi, trước tiên bạn có thể kiểm tra xem unzip -ctệp zip có liên quan đến kết quả của bạn không và chỉ sau đó kiểm tra kỹ hơn các tệp riêng lẻ trong đó.
Ulrich Schwarz

Khả năng xảy ra chuỗi không cao, nhưng tên tệp lưu trữ không phải là dấu hiệu cho thấy những gì bên trong chúng.
fifosine

Câu trả lời:


7

Có một phần bạn có thể dễ dàng cải thiện, nhưng đó không phải là phần chậm nhất.

find /home/mydir/ -type f | sort | \
awk "/xml_20140207_000016.zip/,/xml_20140207_235938.zip/"

Điều này hơi lãng phí vì trước tiên nó liệt kê tất cả các tệp, sau đó sắp xếp tên tệp và trích xuất các tên thú vị. Các findlệnh phải chạy để hoàn thành trước khi phân loại có thể bắt đầu.

Sẽ nhanh hơn khi chỉ liệt kê các tệp thú vị ở vị trí đầu tiên, hoặc ít nhất là một superset nhỏ nhất có thể. Nếu bạn cần một bộ lọc chi tiết hơn về các tên findcó khả năng, hãy chuyển thành awk, nhưng không sắp xếp: awk và các bộ lọc từng dòng khác có thể xử lý từng dòng một nhưng sắp xếp cần đầu vào hoàn chỉnh.

find /home/mydir/ -name 'xml_20140207_??????.zip' -type f | \
awk 'match($0, /_[0-9]*.zip$/) &&
     (time = substr($0, RSTART+1, RLENGTH-5)) &&
     time >= 16 && time <= 235938' |
xargs -n 1 -P 10 zipgrep "my search string"

Phần rõ ràng nhất là tối ưu là zipgrep. Ở đây không có cách dễ dàng để cải thiện hiệu suất vì những hạn chế của lập trình shell. Tập lệnh zipgrep hoạt động bằng cách liệt kê tên tệp trong kho lưu trữ và gọi greptừng nội dung của từng tệp. Điều này có nghĩa là kho lưu trữ zip được phân tích cú pháp nhiều lần cho mỗi tệp. Một chương trình Java (hoặc Perl, hoặc Python hoặc Ruby, v.v.) có thể tránh điều này bằng cách xử lý tệp chỉ một lần.

Nếu bạn muốn gắn bó với lập trình shell, bạn có thể thử gắn từng zip thay vì sử dụng zipgrep.

 | xargs -n1 -P2 sh -c '
    mkdir "mnt$$-$1";
    fuse-zip "$1" "mnt$$-$1";
    grep -R "$0" "mnt$$-$1"
    fusermount -u "mnt$$-$1"
' "my search string"

Lưu ý rằng tính song song sẽ không giúp bạn nhiều: yếu tố giới hạn trên hầu hết các thiết lập sẽ là băng thông I / O của đĩa, không phải thời gian của CPU.

Tôi chưa đạt điểm chuẩn bất cứ điều gì, nhưng tôi nghĩ rằng nơi cải tiến lớn nhất sẽ là sử dụng triển khai zipgrep bằng ngôn ngữ mạnh hơn.


6

Một số ý tưởng nhanh chóng;

  • Nếu tất cả các tệp nằm trong một thư mục, bạn có thể thoát khỏi find
  • Quy ước tên tệp của bạn tự sắp xếp theo ngày, vì vậy bạn cũng không cần sortbit
  • Với hai phần này nằm ngoài tầm kiểm soát và nếu biết phạm vi ngày, bạn có thể sử dụng tên tệp đơn giản toàn cầu thay vì awk. Ví dụ (giả sử vỏ của bạn là bash):

    • Tất cả các tập tin của một ngày

      echo xml_20140207_*.zip | xargs -n 1 -P 10 zipgrep "my search string"

    • Các tệp được tạo trong khoảng thời gian từ 15:00 đến 18:00, vào ngày 07 tháng 2 hoặc ngày 10 tháng 2 năm 2014:

      echo xml_201402{07,10}_1{5..7}*.zip | xargs -n 1 -P 10 zipgrep "my search string"


Cảm ơn những cải tiến của bạn, nhưng khu vực cần nhất (xargs và zipgrep) vẫn còn. Đây là các lệnh cung cấp nút cổ chai. Như Peter Norvig nói, "đừng lãng phí nỗ lực cố gắng tăng tốc các phần trong chương trình của bạn mà không mất nhiều thời gian".
fifosine

3

Không rõ nút cổ chai của bạn ở đâu. Chúng ta hãy giả sử nó là trong việc đọc các tập tin. Tùy thuộc vào hệ thống lưu trữ của bạn, việc đọc toàn bộ tệp trước khi xử lý tệp sẽ nhanh hơn. Điều này đặc biệt đúng với zipgrepmột vài tìm kiếm vào tệp: Nếu tệp không hoàn toàn trong bộ nhớ, bạn sẽ đợi đĩa tìm kiếm.

find ... | parallel -j1 'cat {} >/dev/null; echo {}' | parallel zipgrep "my search string"

Ở trên sẽ catmột tệp tại một thời điểm và do đó đưa nó vào bộ nhớ cache, sau đó chạy một tệp zipgrepcho mỗi CPU, sau đó sẽ đọc từ bộ nhớ cache.

Tôi đã sử dụng các hệ thống RAID trong đó bạn tăng tốc độ 6 lần bằng cách đọc song song 10 tệp so với đọc 1 tệp cùng lúc hoặc đọc song song 30 tệp. Nếu tôi phải chạy ở trên trên hệ thống RAID đó, tôi sẽ điều chỉnh -j1theo -j10.

Bằng cách sử dụng GNU Parallel thay vì xargsbạn tự bảo vệ mình khỏi việc trộn đầu ra (xem http://www.gnu.org/software/abul/man.html#DIFFERENCES-BETweEN-xargs-AND-GNU-Parallel ).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.