Hiệu suất của vòng lặp so với mở rộng


9

Cần đề xuất của chuyên gia về so sánh dưới đây:

Phân đoạn mã bằng vòng lặp:

for file in `cat large_file_list`
do
    gzip -d $file
done

Đoạn mã sử dụng mở rộng đơn giản:

gzip -d `cat large_file_list`

Cái nào sẽ nhanh hơn? Phải thao tác tập dữ liệu lớn.


1
Câu trả lời đúng sẽ phụ thuộc vào thời gian bắt đầu gziptrên hệ thống của bạn, số lượng tệp trong danh sách tệp và kích thước của các tệp đó.
Kusalananda

Danh sách tệp sẽ có khoảng 1000 - 10000 tệp. Kích thước thay đổi từ một số kilobyte đến 500 MB. Tôi không biết phải mất bao lâu để bắt đầu gzip trong hệ thống của mình. có cách nào kiểm tra không?
Leon

1
Ok, sau đó nó cũng có thể phụ thuộc vào độ dài của tên tệp . Nếu tên tệp dài, một số hệ thống có thể tạo ra lỗi "danh sách đối số quá dài" nếu bạn cố gắng thực hiện mà không có vòng lặp do việc thay thế lệnh sẽ dẫn đến một dòng lệnh quá dài để trình bao thực thi. Nếu bạn không muốn phụ thuộc vào số lượng tệp trong danh sách, chỉ cần sử dụng một vòng lặp. Bạn có đang dành một lượng thời gian đáng kể để giải nén các tệp này so với xử lý khác mà bạn sẽ thực hiện trên chúng không?
Kusalananda

Leon hãy xem kết quả kiểm tra của tôi: "tranh luận lớn" nhanh hơn 20 lần so với "vòng lặp" trong cài đặt của tôi.

để có một phương tiện hạnh phúc giữa quá trình bắt đầu và độ dài dòng lệnh, hãy sử dụng một cái gì đó giống như xargs gzip -d < large_file_listnhưng coi chừng khoảng trắng trong tên tệp, có thể vớitr \\n \\0 large_file_list | xargs -0 gzip -d
w00t

Câu trả lời:


19

Biến chứng

Đôi khi sau đây sẽ chỉ hoạt động:

gzip -d `cat large_file_list`

Ba vấn đề là (trong bashvà hầu hết các vỏ giống như Bourne khác):

  1. Nó sẽ thất bại nếu bất kỳ tên tệp nào có tab dấu cách hoặc ký tự dòng mới trong đó (giả sử $IFSchưa được sửa đổi). Điều này là do sự phân tách từ của vỏ .

  2. Nó cũng có thể bị lỗi nếu bất kỳ tên tệp nào có các ký tự hoạt động toàn cầu trong đó. Điều này là do shell sẽ áp dụng mở rộng tên đường dẫn vào danh sách tệp.

  3. Nó cũng sẽ thất bại nếu tên tệp bắt đầu bằng -(nếu POSIXLY_CORRECT=1điều đó chỉ áp dụng cho tệp đầu tiên) hoặc nếu có bất kỳ tên tệp nào -.

  4. Nó cũng sẽ thất bại nếu có quá nhiều tên tệp trong đó phù hợp với một dòng lệnh.

Mã bên dưới chịu các vấn đề tương tự như mã ở trên (ngoại trừ mã thứ tư)

for file in `cat large_file_list`
do
    gzip -d $file
done

Giải pháp đáng tin cậy

Nếu bạn large_file_listcó chính xác một tên tệp trên mỗi dòng và một tệp được gọi -không nằm trong số đó và bạn đang sử dụng hệ thống GNU, thì hãy sử dụng:

xargs -rd'\n' gzip -d -- <large_file_list

-d'\n'nói xargsđể coi mỗi dòng đầu vào là một tên tệp riêng biệt.

-rbảo xargskhông chạy lệnh nếu tệp đầu vào trống.

--nói gziprằng các đối số sau đây không được coi là tùy chọn ngay cả khi chúng bắt đầu bằng -. -một mình vẫn sẽ được coi là -thay vì các tập tin được gọi -mặc dù.

xargssẽ đặt nhiều tên tệp trên mỗi dòng lệnh nhưng không nhiều đến mức vượt quá giới hạn dòng lệnh. Điều này làm giảm số lần một gzipquy trình phải được bắt đầu và do đó làm cho quá trình này nhanh chóng. Nó cũng an toàn: tên tệp cũng sẽ được bảo vệ khỏi việc tách từmở rộng tên đường dẫn .


Cảm ơn đã trả lời chi tiết. Tôi hiểu 3 vấn đề được đề cập của bạn. Tên tệp rất đơn giản và sẽ không phải đối mặt với những thách thức đó vì danh sách sẽ giữ tới 20000. Và câu hỏi của tôi về cơ bản là về hiệu suất của hai phân khúc đó. Cảm ơn.
Leon

1
@Leon forVòng lặp sẽ là một cách chậm nhất. Hai phương pháp khác sẽ rất gần nhau về tốc độ.
John1024

7
Ngoài ra, đừng loại bỏ các vấn đề tiềm ẩn: nhiều câu hỏi ở đây trên StackExchange là do việc chia tách từ hoặc mở rộng tên đường dẫn đã xảy ra với những người không mong đợi nó.
John1024

5
Cũng lưu ý rằng có sự khác biệt khi đọc tệp với xargs: ít nhất phiên bản GNU có --arg-filetùy chọn (dạng rút gọn -a). Vì vậy, người ta có thể làm xargs -a large_file_list -rd'\n' gzip -d thay thế. Về mặt hiệu quả, không có sự khác biệt, ngoài thực tế <là toán tử shell và sẽ xargsđọc từ stdin (shell "liên kết" đến tệp), trong khi -asẽ xargsmở tệp rõ ràng trong câu hỏi
Sergiy Kolodyazhnyy

2
terdon lưu ý trong một nhận xét khác về việc sử dụng parallelđể chạy nhiều bản sao của gzip, nhưng xargs(ít nhất là bản GNU), cũng có công -Ptắc cho điều đó. Trên các máy đa lõi có thể tạo ra sự khác biệt. Nhưng cũng có khả năng giải nén hoàn toàn bị ràng buộc I / O.
ilkkachu

12

Tôi nghi ngờ nó sẽ quan trọng nhiều.

Tôi sẽ sử dụng một vòng lặp, chỉ vì tôi không biết có bao nhiêu tệp được liệt kê trong tệp danh sách và tôi (nói chung) không biết liệu có bất kỳ tên tệp nào có dấu cách trong tên của chúng không. Thực hiện thay thế lệnh sẽ tạo ra một danh sách đối số rất dài có thể dẫn đến lỗi "Danh sách đối số quá dài" khi độ dài của danh sách được tạo quá dài.

Vòng lặp của tôi sẽ giống như

while IFS= read -r name; do
    gunzip "$name"
done <file.list

Điều này cũng cho phép tôi chèn các lệnh để xử lý dữ liệu sau gunziplệnh. Trong thực tế, tùy thuộc vào dữ liệu thực sự là gì và cần phải làm gì với dữ liệu đó, thậm chí có thể xử lý dữ liệu mà không lưu dữ liệu vào tệp:

while IFS= read -r name; do
    zcat "$name" | process_data
done <file.list

(nơi process_datamột số đường ống đọc dữ liệu không nén từ đầu vào tiêu chuẩn)

Nếu việc xử lý dữ liệu mất nhiều thời gian hơn việc giải nén dữ liệu, câu hỏi liệu một vòng lặp có hiệu quả hơn hay không trở nên không liên quan.

Lý tưởng nhất là tôi không muốn làm việc với một danh sách tên tệp, và thay vào đó sử dụng một mẫu tên tập tin, như trong

for name in ./*.gz; do
    # processing of "$name" here
done

nơi ./*.gzlà một số mô hình phù hợp với các tập tin có liên quan. Bằng cách này, chúng tôi không phụ thuộc vào số lượng tệp cũng như các ký tự được sử dụng trong tên tệp (chúng có thể chứa dòng mới hoặc các ký tự khoảng trắng khác hoặc bắt đầu bằng dấu gạch ngang, v.v.)

Liên quan:


5

Trong số hai tệp đó, tệp có tất cả các tệp được chuyển đến một lệnh gọi gzipcó khả năng nhanh hơn, chính xác vì bạn chỉ cần khởi chạy gzipmột lần. (Đó là, nếu lệnh hoạt động hoàn toàn, hãy xem các câu trả lời khác cho các cảnh báo.)

Nhưng, tôi muốn nhắc về quy tắc tối ưu hóa vàng : Đừng làm điều đó sớm.

  1. Đừng tối ưu hóa loại điều đó trước khi bạn biết đó là một vấn đề.

    Phần này của chương trình có mất nhiều thời gian không? Chà, giải nén các tệp lớn có thể, và dù sao bạn cũng sẽ phải làm điều đó, vì vậy có thể không dễ để trả lời.

  2. Đo lường. Thực sự, đó là cách tốt nhất để chắc chắn.

    Bạn sẽ nhìn thấy kết quả bằng chính mắt mình (hoặc bằng đồng hồ bấm giờ của riêng bạn) và họ sẽ áp dụng cho tình huống của bạn mà câu trả lời ngẫu nhiên trên Internet có thể không. Đặt cả hai biến thể trong kịch bản và chạy time script1.sh, và time script2.sh. (Làm điều đó với một danh sách các tệp nén trống để đo lượng tuyệt đối của chi phí.)


0

Đĩa của bạn nhanh như thế nào?

Điều này sẽ sử dụng tất cả các CPU của bạn:

parallel -X gzip -d :::: large_file_list

Vì vậy, giới hạn của bạn có thể sẽ là tốc độ của đĩa của bạn.

Bạn có thể thử điều chỉnh với -j:

parallel -j50% -X gzip -d :::: large_file_list

Điều này sẽ chạy một nửa các công việc song song như lệnh trước đó và sẽ làm căng đĩa của bạn ít hơn, do đó tùy thuộc vào đĩa của bạn, việc này có thể nhanh hơn.

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.