Tập lệnh Bash xử lý số lượng lệnh giới hạn song song


196

Tôi có một tập lệnh bash trông như thế này:

#!/bin/bash
wget LINK1 >/dev/null 2>&1
wget LINK2 >/dev/null 2>&1
wget LINK3 >/dev/null 2>&1
wget LINK4 >/dev/null 2>&1
# ..
# ..
wget LINK4000 >/dev/null 2>&1

Nhưng việc xử lý từng dòng cho đến khi lệnh kết thúc rồi chuyển sang dòng tiếp theo rất tốn thời gian, tôi muốn xử lý ví dụ 20 dòng cùng một lúc sau đó khi chúng hoàn thành 20 dòng khác được xử lý.

Tôi đã nghĩ wget LINK1 >/dev/null 2>&1 &đến việc gửi lệnh đến nền và tiếp tục, nhưng có 4000 dòng ở đây có nghĩa là tôi sẽ gặp vấn đề về hiệu năng, chưa kể bị giới hạn trong bao nhiêu quy trình tôi nên bắt đầu cùng một lúc nên điều này không tốt ý tưởng.

Một giải pháp mà tôi đang nghĩ đến bây giờ là kiểm tra xem một trong các lệnh có còn chạy hay không, ví dụ sau 20 dòng tôi có thể thêm vòng lặp này:

while [  $(ps -ef | grep KEYWORD | grep -v grep | wc -l) -gt 0 ]; do
sleep 1
done

Tất nhiên trong trường hợp này tôi sẽ cần phải nối thêm vào cuối dòng! Nhưng tôi cảm thấy đây không phải là cách đúng đắn để làm điều đó.

Vậy làm thế nào để tôi thực sự nhóm mỗi dòng 20 lại với nhau và đợi chúng kết thúc trước khi đi đến 20 dòng tiếp theo, tập lệnh này được tạo động để tôi có thể thực hiện bất kỳ phép toán nào tôi muốn trong khi nó được tạo, nhưng nó KHÔNG phải sử dụng wget, nó chỉ là một ví dụ vì vậy bất kỳ giải pháp nào cụ thể sẽ không giúp ích gì cho tôi.


1
waitlà câu trả lời đúng ở đây, nhưng bạn while [ $(ps …sẽ viết tốt hơn nhiều while pkill -0 $KEYWORD…- sử dụng proctools , vì lý do chính đáng để kiểm tra xem một quy trình có tên cụ thể có còn chạy hay không.
kojiro

Tôi nghĩ rằng câu hỏi này nên được mở lại. QA "có thể trùng lặp" là tất cả về việc chạy song song một số lượng chương trình hữu hạn . Thích 2-3 lệnh. Câu hỏi này, tuy nhiên, tập trung vào việc chạy các lệnh trong ví dụ như một vòng lặp. (xem "nhưng có 4000 dòng").
VasiliNovikov

@VasyaNovikov Bạn đã đọc tất cả các câu trả lời cho cả câu hỏi này và bản sao chưa? Mỗi câu trả lời cho câu hỏi này ở đây, cũng có thể được tìm thấy trong các câu trả lời cho câu hỏi trùng lặp. Đó chính xác là định nghĩa của một câu hỏi trùng lặp. Nó hoàn toàn không có sự khác biệt cho dù bạn có chạy các lệnh trong một vòng lặp hay không.
robinCTS

@robinCTS có giao điểm, nhưng bản thân câu hỏi thì khác. Ngoài ra, 6 trong số các câu trả lời phổ biến nhất về thỏa thuận QA được liên kết chỉ có 2 quy trình.
VasiliNovikov

2
Tôi khuyên bạn nên mở lại câu hỏi này vì câu trả lời của nó rõ ràng hơn, sạch hơn, tốt hơn và được đánh giá cao hơn nhiều so với câu trả lời tại câu hỏi được liên kết, mặc dù nó mới hơn ba năm.
Dan Nissenbaum

Câu trả lời:


331

Sử dụng wait hợp:

process1 &
process2 &
process3 &
process4 &
wait
process5 &
process6 &
process7 &
process8 &
wait

Ví dụ trên, 4 quy trình process1 ... process4sẽ được bắt đầu trong nền và trình bao sẽ đợi cho đến khi các quy trình được hoàn thành trước khi bắt đầu tập tiếp theo.

Từ hướng dẫn GNU :

wait [jobspec or pid ...]

Đợi cho đến khi tiến trình con được chỉ định bởi mỗi pid ID quy trình hoặc jobspec đặc tả công việc thoát và trả về trạng thái thoát của lệnh cuối cùng được chờ. Nếu một đặc tả công việc được đưa ra, tất cả các quy trình trong công việc được chờ đợi. Nếu không có đối số nào được đưa ra, tất cả các quy trình con hiện đang hoạt động đều được chờ đợi và trạng thái trả về bằng không. Nếu cả jobspec và pid chỉ định một tiến trình con hoạt động của shell, trạng thái trả về là 127.


14
Về cơ bảni=0; waitevery=4; for link in "${links[@]}"; do wget "$link" & (( i++%waitevery==0 )) && wait; done >/dev/null 2>&1
kojiro

18
Trừ khi bạn chắc chắn rằng mỗi quá trình sẽ kết thúc cùng một lúc, đây là một ý tưởng tồi. Bạn cần bắt đầu công việc mới để giữ tổng số công việc hiện tại ở một mức nhất định .... song song là câu trả lời.
rsaw

1
Có cách nào để làm điều này trong một vòng lặp?
Tên miền được thực hiện vào

Tôi đã thử điều này nhưng có vẻ như các bài tập biến được thực hiện trong một khối không có sẵn trong khối tiếp theo. Đây có phải là vì chúng là các quá trình riêng biệt? Có cách nào để truyền đạt các biến trở lại quy trình chính không?
Bobby

97

Xem song song . Cú pháp của nó tương tự xargs, nhưng nó chạy các lệnh song song.


13
Điều này tốt hơn so với việc sử dụng wait, vì nó quan tâm đến việc bắt đầu các công việc mới khi công việc cũ hoàn thành, thay vì chờ đợi toàn bộ một đợt hoàn thành trước khi bắt đầu công việc tiếp theo.
chepner

5
Ví dụ: nếu bạn có danh sách các liên kết trong một tệp, bạn có thể làm điều cat list_of_links.txt | parallel -j 4 wget {}đó sẽ giữ cho bốn wgetgiây chạy cùng một lúc.
Ông Llama

5
Có một đứa trẻ mới trong thị trấn tên là pexec thay thế cho parallel.
slashsbin

2
Cung cấp một ví dụ sẽ là hữu ích hơn
jterm

1
parallel --jobs 4 < list_of_commands.sh, trong đó list_of_commands.sh là một tệp có một lệnh duy nhất (ví dụ: wget LINK1ghi chú không có &) trên mỗi dòng. Có thể cần phải làm CTRL+Zbgsau khi để nó chạy trong nền.
weiji14

71

Trong thực tế, xargs có thể chạy các lệnh song song cho bạn. Có một -P max_procstùy chọn dòng lệnh đặc biệt cho điều đó. Xem man xargs.


2
+100 điều này thật tuyệt vời vì nó được xây dựng và sử dụng rất đơn giản và có thể được thực hiện trong một lớp lót
Clay

Tuyệt vời để sử dụng cho các container nhỏ, vì không cần thêm gói / phụ thuộc!
Marco Roy

1
Xem câu hỏi này để biết ví dụ: stackoverflow.com/questions/28357997/
Roy Roy

7

Bạn có thể chạy 20 quy trình và sử dụng lệnh:

wait

Kịch bản của bạn sẽ chờ và tiếp tục khi tất cả các công việc nền của bạn kết thúc.

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.