Tạo một luồng đầu ra duy nhất trong số ba luồng khác được tạo ra song song


10

Tôi có ba loại dữ liệu ở các định dạng khác nhau; đối với mỗi loại dữ liệu, có một tập lệnh Python chuyển đổi nó thành một định dạng thống nhất duy nhất.

Tập lệnh Python này bị chậm và bị ràng buộc bởi CPU (với một lõi đơn trên máy đa lõi), vì vậy tôi muốn chạy ba phiên bản của nó - một cho mỗi loại dữ liệu - và kết hợp đầu ra của chúng để chuyển nó vào sort. Về cơ bản, tương đương với điều này:

{ ./handle_1.py; ./handle_2.py; ./handle_3.py } | sort -n

Nhưng với ba kịch bản chạy song song.

Tôi đã tìm thấy câu hỏi này trong đó GNU splitđã được sử dụng để làm tròn một số luồng đầu ra giữa các phiên bản của tập lệnh xử lý luồng.

Từ trang chia người:

-n, --number=CHUNKS
          generate CHUNKS output files.  See below
CHUNKS  may be:
 N       split into N files based on size of input
 K/N     output Kth of N to stdout
 l/N     split into N files without splitting lines
 l/K/N   output Kth of N to stdout without splitting lines
 r/N     like 'l'  but  use  round  robin  distributio

Vì vậy, r/Nlệnh ngụ ý " không chia dòng ".

Dựa trên điều này, có vẻ như giải pháp sau đây là khả thi:

split -n r/3 -u --filter="./choose_script" << EOF
> 1
> 2
> 3
> EOF

Trường hợp choose_scriptnày

#!/bin/bash
{ read x; ./handle_$x.py; }

Thật không may, tôi thấy một số dòng xen kẽ - và rất nhiều dòng mới không nên có.

Ví dụ: nếu tôi thay thế các tập lệnh Python của mình bằng một số tập lệnh bash đơn giản thực hiện việc này:

#!/bin/bash
# ./handle_1.sh
while true; echo "1-$RANDOM"; done;

.

#!/bin/bash
# ./handle_2.sh
while true; echo "2-$RANDOM"; done;

.

#!/bin/bash
# ./handle_3.sh
while true; echo "3-$RANDOM"; done;

Tôi thấy đầu ra này:

1-8394

2-11238
2-22757
1-723
2-6669
3-3690
2-892
2-312511-24152
2-9317
3-5981

Điều này thật khó chịu - dựa trên trích xuất trang người đàn ông tôi đã dán ở trên, nó sẽ duy trì tính toàn vẹn của dòng.

Rõ ràng là nó hoạt động nếu tôi loại bỏ -uđối số, nhưng sau đó nó được đệm và tôi sẽ hết bộ nhớ vì nó đệm đầu ra của tất cả trừ một trong các tập lệnh.

Nếu bất cứ ai có cái nhìn sâu sắc ở đây, nó sẽ được đánh giá rất cao. Tôi ra khỏi chiều sâu của tôi ở đây.


Một số người trong #bash trên freenode đề nghị tôi sinh ra cả ba quy trình và tạo nền cho chúng, viết cho các FD tùy chỉnh, sau đó lặp lại các FD đó và đọc các dòng cho chúng, nhưng tôi chưa tìm ra cách làm cho nó hoạt động được. Tôi cũng được yêu cầu nhìn vào coprocnội trang trong bash, mặc dù tôi không thực sự thấy nó được áp dụng như thế nào.
Cera

1
Bạn có phải làm điều đó mà không có tập tin trung gian? Bạn không thể làm gì job1.py > file1 & job2.py > file 2 & job3.py > file3 ; wait ; sort -n file1 file2 file3?
angus

Câu trả lời:


2

Hãy thử sử dụng tùy chọn -u của GNU song song.

echo "1\n2\n3" | parallel -u -IX ./handle_X.sh

Điều này chạy chúng song song, mà không đệm toàn bộ quá trình.


Tôi là một chút bối rối - là XIXnói -Irằng X sẽ là lá cờ để thay thế, hoặc là nó áp dụng các -Xlá cờ, mà dường như còn có một ý nghĩa có liên quan?
Cera

Hừm. Tôi đang làm điều này: parallel -u -X ./handle_{}.sh ::: "1" "2" "3"và thật không may, tôi vẫn thấy một số kết quả đầu ra.
Cera

trước đây: bạn cũng có thể sử dụng parallel -u ./handle_{}.sh, nhưng tôi thích thay đổi nó hơn, vì niềng răng cũng có ý nghĩa là nối các lệnh với nhau (như trong câu hỏi của bạn).
Flowblok

Có vẻ như hoạt động với tôi, grep của tôi không nhận bất kỳ sự xáo trộn nào: pastie.org/5113187 (bạn đang sử dụng tập lệnh bash thử nghiệm hay tập lệnh Python thực tế của bạn?)
Flowblok

Vấn đề là điều đó không thực sự làm gì song song. Tôi đang sử dụng tập lệnh bash - pastie.org/5113225
Cera

2

Thử:

parallel ::: ./handle_1.py ./handle_2.py ./handle_3.py

Nếu handle_1.pycó tên tệp:

parallel ::: ./handle_1.py ./handle_2.py ./handle_3.py ::: files*

Bạn không muốn đầu ra hỗn hợp, vì vậy không sử dụng -u.

Nếu bạn muốn giữ thứ tự (vì vậy tất cả đầu ra của xử lý_1 nằm trước tay cầm_2 và do đó bạn có thể tránh sắp xếp):

parallel -k  ::: ./handle_1.py ./handle_2.py ./handle_3.py ::: files*

Nếu bạn vẫn muốn nó được sắp xếp, bạn có thể song song việc sắp xếp và sử dụng sort -m:

parallel --files "./handle_{1}.py {2} | sort -n"  ::: 1 2 3 ::: files* | parallel -j1 -X sort -m

Đặt $ TMPDIR thành một thư mục đủ lớn để giữ đầu ra.


1
Tôi thực sự muốn đầu ra 'hỗn hợp' - Tôi chỉ muốn đảm bảo rằng mỗi dòng trong đầu ra cuối cùng là một dòng từ một trong các quy trình con. Nếu tôi không trộn nó, hệ thống sẽ hết bộ nhớ đệm các luồng đầu ra chưa được in ra.
Cera

Với GNU Parallel, bạn sẽ không hết bộ nhớ: Nó không đệm trong bộ nhớ. Tại sao bạn nghĩ rằng nó đệm trong bộ nhớ?
Ole Tange

2

Có thể tôi đang thiếu một cái gì đó, nhưng bạn không thể làm:

(./handle_1.py & ./handle_2.py & ./handle_3.py) | sort -n

Nếu bạn muốn các dòng từ mỗi quy trình không bị xen kẽ, có thể dễ dàng hơn để đảm bảo rằng chính quy trình đó viết chúng đầy đủ và có thể vô hiệu hóa bộ đệm đầu ra khi writes vào một đường ống được đảm bảo là nguyên tử miễn là chúng không lớn hơn PIPE_BUF. Ví dụ, bạn có thể chắc chắn rằng nó không sử dụng đầu ra đệm à la stdiovà cuộc gọi fflushhoặc bất cứ điều gì tương đương là ở pythonsau một hoặc một vài dòng đã được viết.

Nếu bạn không thể sửa đổi tập lệnh python, bạn có thể làm:

lb() { grep --line-buffered '^'; }

(với GNU grep) hoặc:

lb() while IFS= read -r l; do printf '%s\n' "$l"; done

(Xem ghi chú trong các bình luận bên dưới nếu những gì đầu ra lệnh không phải là văn bản)

Và làm:

(./handle_1.py | lb & ./handle_2.py | lb & ./handle_3.py | lb) | sort -n

Một tùy chọn khác để tránh 3 lbquy trình đó là có ba ống dẫn đến một lệnh sử dụng select/ pollđể xem nơi nào có đầu ra đến và đưa nó vào sortdựa trên dòng, nhưng phải mất một chút lập trình.


Bạn cần một waittrong đó, tôi nghĩ.
derobert

1
Không, trừ khi một số chương trình đóng thiết bị xuất chuẩn trước khi thoát, vì đường ống và sort -nsẽ duy trì cho đến khi tất cả các chương trình mở fd trên đó đã thoát.
Stéphane Chazelas

Thật vậy, tôi đã thử nghiệm, bạn là chính xác.
derobert

Không, tôi vẫn nhận được kết quả đầu ra. Các dòng được trộn lẫn với nhau và xen kẽ.
Cera

1
OK @Cerales, hãy xem câu trả lời cập nhật của tôi
Stéphane Chazelas

1

Câu trả lời của Flowbok là giải pháp chính xác. Điều kỳ lạ là, đầu ra của GNU parallelbị sai lệch nếu đầu ra trực tiếp vào một tệp - nhưng không phải là đầu ra.

May mắn thay, script -ccó sẵn để bắt chước một tty.

Vẫn còn ba kịch bản:

#!/bin/bash
# handle_1.sh
while true; do echo "1-$RANDOM$RANDOM$RANDOM$RANDOM"; done

.

#!/bin/bash
# handle_2.sh
while true; do echo "2-$RANDOM$RANDOM$RANDOM$RANDOM"; done

.

#!/bin/bash
# handle_3.sh
while true; do echo "3-$RANDOM$RANDOM$RANDOM$RANDOM"; done

Sau đó, có một tập tin đóng gói cuộc gọi đến song song:

#!/bin/bash
# run_parallel.sh
parallel -u -I N ./handle_N.sh ::: "1" "2" "3"

Và sau đó tôi gọi nó như thế này:

script -c ./run_parallel > output

Các dòng trong đầu ra được trộn lẫn từng dòng giữa đầu ra của các tập lệnh khác nhau, nhưng chúng không bị xáo trộn hoặc xen kẽ trên một dòng nhất định.

Hành vi kỳ lạ từ parallel- Tôi có thể nộp báo cáo lỗi.

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.