2013-06-25 11 views
20

Đã có một số câu hỏi tương tự, nhưng vấn đề của tôi không phải là "chạy nhiều chương trình song song" - có thể được thực hiện một cách trivially với parallel hoặc xargs.Làm thế nào để chạy hàm đã cho trong Bash song song?

Tôi cần song song các hàm Bash.

Hãy tưởng tượng mã như thế này:

for i in "${list[@]}" 
do 
    for j in "${other[@]}" 
    do 
    # some processing in here - 20-30 lines of almost pure bash 
    done 
done 

Một số chế biến đòi hỏi các cuộc gọi đến các chương trình bên ngoài.

Tôi muốn chạy một số tác vụ (4-10), mỗi tác vụ chạy cho $i khác nhau. Tổng số phần tử trong danh sách $ là> 500.

Tôi biết tôi có thể đặt toàn bộ vòng lặp for j ... done trong tập lệnh bên ngoài và chỉ cần gọi chương trình này song song, nhưng có thể thực hiện mà không chia tách chức năng giữa hai chương trình riêng biệt ?

+0

Thử sử dụng các hàm. Hoặc một cái gì đó như 'var1 = \' ls && pwd & & ls && pwd & \ '' bên trong vòng lặp của bạn. –

+0

Vâng, nhưng tôi không muốn chạy * tất cả * lặp lại cùng một lúc. Tôi muốn có 4 quy trình công nhân đồng thời, và nếu có ai trong số họ hoàn thành - hãy bắt đầu một quy trình mới. Loại như: 'cat work_params | xargs -L1 -P4 do_bit_of_work' hoạt động. –

+0

Hmmm ... 4 công nhân. Tôi đoán bạn sẽ phải thiết lập một số loại semaphores sau đó. Và bình chọn cho họ theo định kỳ. –

Trả lời

10

Chỉnh sửa: Vui lòng xem xét Ole's answer để thay thế.

Thay vì một tập lệnh riêng biệt, bạn có thể đặt mã của mình vào một hàm bash riêng biệt. Sau đó, bạn có thể xuất và chạy thông qua xargs:

#!/bin/bash 
dowork() { 
    sleep $((RANDOM % 10 + 1)) 
    echo "Processing i=$1, j=$2" 
} 
export -f dowork 

for i in "${list[@]}" 
do 
    for j in "${other[@]}" 
    do 
     printf "%s\0%s\0" "$i" "$j" 
    done 
done | xargs -0 -n 2 -P 4 bash -c 'dowork "[email protected]"' -- 
+0

Điều đó có thể hoạt động, cảm ơn. –

32

sem là một phần của GNU Parallel và được tạo cho loại tình huống này.

for i in "${list[@]}" 
do 
    for j in "${other[@]}" 
    do 
     # some processing in here - 20-30 lines of almost pure bash 
     sem -j 4 dolong task 
    done 
done 

Nếu bạn thích những chức năng tốt hơn GNU Parallel có thể làm kép cho vòng lặp trong một đi:

dowork() { 
    echo "Starting i=$1, j=$2" 
    sleep 5 
    echo "Done i=$1, j=$2" 
} 
export -f dowork 

parallel dowork ::: "${list[@]}" ::: "${other[@]}" 
+3

Tuyệt vời. Cách mượt mà hơn đề nghị của tôi. –

+2

Điều này không hoạt động (nữa?) (GNU song song 20160722)., Đầu ra "/ bin/bash: dowork: lệnh không tìm thấy". – jamshid

+1

@jamshid Bạn có nhớ 'export -f dowork' không? Nếu có, thì bạn có thể đã tìm thấy một lỗi xuất hiện trên hệ thống của bạn. Là một công việc xung quanh: Hãy thử 'env_parallel' thay vì' song song'. –

0

Giải pháp để chạy nhiều dòng lệnh song song:

for i in "${list[@]}" 
do 
    for j in "${other[@]}" 
    do 
     test "$(jobs | wc -l)" -ge 8 && wait -n || true 
     (
      your 
      multi-line 
      commands 
      here 
     ) & 
    done 
done 

Nếu có 8 công việc bash đang chạy, wait sẽ đợi ít nhất một công việc để hoàn thành. Nếu/khi có ít công việc hơn, nó sẽ bắt đầu công việc mới một cách không đồng bộ.

Lợi ích của phương pháp này:

  1. Nó rất dễ dàng cho các lệnh đa dòng. Tất cả các biến của bạn được tự động "ghi lại" trong phạm vi, không cần phải chuyển chúng thành các đối số
  2. Nó tương đối nhanh. Hãy so sánh điều này, ví dụ, để song song (tôi đang trích dẫn chính thức man):

    song song khởi động chậm - khoảng 250 mili giây và 150 mili giây sau đó.

  3. Chỉ cần bash để hoạt động.

Nhược điểm:

  1. Có một khả năng rằng đã có 8 công việc khi chúng ta đếm được họ, nhưng ít khi chúng ta bắt đầu chờ đợi. (Nó sẽ xảy ra nếu một công việc kết thúc trong những mili giây giữa hai lệnh.) Điều này có thể làm cho chúng tôi wait với ít công việc hơn yêu cầu.Tuy nhiên, nó sẽ tiếp tục khi có ít nhất một công việc hoàn thành, hoặc ngay lập tức nếu có 0 công việc đang chạy (wait -n thoát ngay lập tức trong trường hợp này).
  2. Rất khó, nhưng nếu bạn sử dụng điều khiển công việc bash (&) cho các mục đích khác trong cùng một vòng lặp, mọi thứ có thể hoạt động không như mong đợi.