Bốn nhiệm vụ song song làm thế nào để tôi làm điều đó?


23

Tôi có một loạt các hình ảnh PNG trên một thư mục. Tôi có một ứng dụng gọi là pngout mà tôi chạy để nén những hình ảnh này. Ứng dụng này được gọi bởi một kịch bản tôi đã làm. Vấn đề là kịch bản này thực hiện từng cái một, đại loại như thế này:

FILES=(./*.png)
for f in  "${FILES[@]}"
do
        echo "Processing $f file..."
        # take action on each file. $f store current file name
        ./pngout -s0 $f R${f/\.\//}
done

Xử lý chỉ một tệp tại một thời điểm, mất rất nhiều thời gian. Sau khi chạy ứng dụng này, tôi thấy rằng CPU chỉ là 10%. Vì vậy, tôi phát hiện ra rằng tôi có thể chia các tệp này thành 4 đợt, đặt từng lô vào một thư mục và bắn 4, từ bốn cửa sổ đầu cuối, bốn quy trình, do đó tôi có bốn phiên bản tập lệnh của mình, đồng thời xử lý các hình ảnh đó và công việc mất 1/4 thời gian.

Vấn đề thứ hai là tôi mất thời gian phân chia hình ảnh và các đợt và sao chép tập lệnh vào bốn thư mục, mở 4 cửa sổ đầu cuối, bla bla ...

Làm thế nào để làm điều đó với một kịch bản, mà không phải phân chia bất cứ điều gì?

Ý tôi là hai điều: đầu tiên làm thế nào để tôi từ một kịch bản bash, kích hoạt một quá trình đến nền? (chỉ cần thêm & vào cuối?) Thứ hai: làm thế nào để tôi dừng gửi tác vụ xuống nền sau khi gửi các tác vụ thứ tư và đặt tập lệnh để đợi cho đến khi tác vụ kết thúc? Ý tôi là, chỉ cần gửi một nhiệm vụ mới đến nền là một nhiệm vụ kết thúc, luôn luôn giữ 4 nhiệm vụ song song? nếu tôi không làm điều đó thì vòng lặp sẽ kích hoạt hàng trăm nhiệm vụ xuống nền và CPU sẽ bị tắc.


Câu trả lời:


33

Nếu bạn có một bản sao xargshỗ trợ thực hiện song song -P, bạn chỉ cần làm

printf '%s\0' *.png | xargs -0 -I {} -P 4 ./pngout -s0 {} R{}

Đối với các ý tưởng khác, wiki Wooledge Bash có một phần trong bài viết Quản lý quy trình mô tả chính xác những gì bạn muốn.


2
Ngoài ra còn có "gnu song song" và "xjobs" được thiết kế cho trường hợp này. Đó chủ yếu là vấn đề của hương vị mà bạn thích.
wnoise

Bạn có thể vui lòng giải thích lệnh được đề xuất? Cảm ơn!
Eugene S

1
@EugeneS Bạn có thể nói rõ hơn một chút về phần nào không? Printf thu thập tất cả các tệp png và chuyển chúng qua một đường ống đến xargs, thu thập các đối số từ đầu vào tiêu chuẩn và kết hợp chúng thành các đối số cho pngoutlệnh mà OP muốn chạy. Tùy chọn chính là -P 4, cho biết xargs sử dụng tối đa 4 lệnh đồng thời.
jw013

2
Xin lỗi vì đã không chính xác. Tôi đặc biệt quan tâm tại sao bạn sử dụng printfchức năng ở đây thay vì chỉ thường xuyên ls .. | grep .. *.png? Ngoài ra tôi quan tâm đến các xargstham số bạn đã sử dụng ( -0-I{}). Cảm ơn!
Eugene S

3
@EugeneS Đó là sự chính xác và mạnh mẽ tối đa. Tên tệp không phải là dòng và lskhông thể được sử dụng để phân tích tên tệp một cách hợp lý và an toàn . Các ký tự an toàn duy nhất được sử dụng để phân định tên tệp là \0/, vì mọi ký tự khác, bao gồm \n, có thể là một phần của chính tên tệp. Việc printfsử dụng \0để phân định tên tệp và -0thông báo xargsvề điều này. Các -I{}nói xargsđể thay thế {}với các đối số.
jw013

8

Ngoài các giải pháp đã được đề xuất, bạn có thể tạo tệp tạo tệp mô tả cách tạo tệp nén từ không nén và sử dụng make -j 4để chạy song song 4 công việc. Vấn đề là bạn sẽ cần đặt tên các tệp nén và không nén khác nhau, hoặc lưu trữ chúng trong các thư mục khác nhau, việc viết một quy tắc tạo hợp lý sẽ là không thể.



5

Để trả lời hai câu hỏi của bạn:

  • có, thêm và ở cuối dòng sẽ hướng dẫn bạn shell để khởi chạy một quá trình nền.
  • bằng cách sử dụng waitlệnh, bạn có thể yêu cầu shell chờ tất cả các quá trình trong nền kết thúc trước khi tiếp tục.

Đây là tập lệnh được sửa đổi để jđược sử dụng để theo dõi số lượng quá trình nền. Khi NB_CONCURRENT_PROCESSESđạt được, tập lệnh sẽ đặt lại jvề 0 và đợi cho tất cả các quá trình nền kết thúc trước khi tiếp tục thực hiện.

files=(./*.png)
nb_concurrent_processes=4
j=0
for f in "${files[@]}"
do
        echo "Processing $f file..."
        # take action on each file. $f store current file name
        ./pngout -s0 "$f" R"${f/\.\//}" &
        ((++j == nb_concurrent_processes)) && { j=0; wait; }
done

1
Điều này sẽ chờ cho quá trình cuối cùng trong bốn quy trình đồng thời và sau đó sẽ bắt đầu một bộ bốn quy trình khác. Có lẽ người ta nên xây dựng một mảng gồm bốn PID và sau đó chờ đợi các PID cụ thể này?
Nils

Chỉ để giải thích các sửa lỗi của tôi cho mã: (1) Vì vấn đề về kiểu dáng, hãy tránh tất cả các tên biến chữ hoa vì chúng có khả năng xung đột với các biến shell nội bộ. (2) Đã thêm trích dẫn cho $fvv (3) Sử dụng [cho các tập lệnh tương thích POSIX, nhưng đối với bash thuần túy [[luôn được ưu tiên. Trong trường hợp này, ((là thích hợp hơn cho số học.
jw013
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.