Bạn biết đấy, tôi không tin rằng bạn nhất thiết cần một vòng phản hồi lặp đi lặp lại như sơ đồ của bạn, nhiều đến mức bạn có thể sử dụng một đường ống liên tục giữa các bộ xử lý . Sau đó, một lần nữa, có thể không có quá nhiều sự khác biệt - một khi bạn mở một dòng trên bộ đồng xử lý, bạn có thể thực hiện các vòng lặp kiểu điển hình chỉ cần viết thông tin và đọc thông tin từ nó mà không làm bất cứ điều gì khác thường.
Ở nơi đầu tiên, nó sẽ xuất hiện bc
là một ứng cử viên chính cho việc đồng xử lý cho bạn. Trong bc
bạn có thể các define
chức năng có thể làm khá nhiều những gì bạn yêu cầu trong mã giả của bạn. Ví dụ, một số chức năng rất đơn giản để thực hiện việc này có thể trông giống như:
printf '%s()\n' b c a |
3<&0 <&- bc -l <<\IN <&3
a=1; b=0; c=0;
define a(){ "a="; return (a = c+1); }
define b(){ "b="; return (b = 3*a); }
define c(){ "c="; return (c = s(b)); }
IN
... sẽ in ...
b=3
c=.14112000805986722210
a=1.14112000805986722210
Nhưng tất nhiên, nó không kéo dài . Ngay sau khi phần phụ chịu trách nhiệm printf
thoát khỏi đường ống (ngay sau khi printf
ghi a()\n
vào đường ống) , đường ống bị phá hủy và bc
đầu vào của nó đóng lại và nó cũng thoát ra. Điều đó gần như không hữu ích như nó có thể.
@derobert đã đề cập đến các FIFO như có thể có bằng cách tạo một tệp ống có tên với mkfifo
tiện ích. Đây thực chất chỉ là các đường ống, ngoại trừ nhân hệ thống liên kết một mục hệ thống tập tin với cả hai đầu. Đây là rất hữu ích, nhưng nó sẽ đẹp hơn nếu bạn có thể có một đường ống mà không có nguy cơ nó bị rình mò trong hệ thống tập tin.
Khi nó xảy ra, vỏ của bạn làm điều này rất nhiều. Nếu bạn sử dụng một lớp vỏ thực hiện thay thế quá trình thì bạn có một phương tiện rất đơn giản để có được một đường ống lâu dài - loại mà bạn có thể gán cho một quá trình nền mà bạn có thể giao tiếp.
Trong bash
Ví dụ, bạn có thể thấy cách thức hoạt động thay thế tiến trình:
bash -cx ': <(:)'
+ : /dev/fd/63
Bạn thấy nó thực sự là một sự thay thế . Shell thay thế một giá trị trong quá trình mở rộng tương ứng với đường dẫn đến một liên kết đến một đường ống . Bạn có thể tận dụng điều đó - bạn không cần bị hạn chế chỉ sử dụng đường ống đó để liên lạc với bất kỳ quy trình nào chạy trong chính sự ()
thay thế ...
bash -c '
eval "exec 3<>"<(:) "4<>"<(:)
cat <&4 >&3 &
echo hey cat >&4
read hiback <&3
echo "$hiback" here'
... mà in ...
hey cat here
Bây giờ tôi biết rằng các shell khác nhau thực hiện việc đồng xử lý theo các cách khác nhau - và có một cú pháp cụ thể bash
để thiết lập một (cũng có thể là một cho zsh
cả) - nhưng tôi không biết những thứ đó hoạt động như thế nào. Tôi chỉ biết rằng bạn có thể sử dụng cú pháp trên để thực hiện hầu như cùng một việc mà không cần tất cả sự nghiêm khắc trong cả hai bash
và zsh
- và bạn có thể làm một điều rất giống nhau trong dash
và busybox ash
để đạt được cùng một mục đích với các tài liệu ở đây (bởi vì dash
và busybox
làm ở đây- tài liệu với các đường ống chứ không phải các tập tin tạm thời như hai người khác làm) .
Vì vậy, khi áp dụng vào bc
...
eval "exec 3<>"<(:) "4<>"<(:)
bc -l <<\INIT <&4 >&3 &
a=1; b=0; c=0;
define a(){ "a="; return (a = c+1); }
define b(){ "b="; return (b = 3*a); }
define c(){ "c="; return (c = s(b)); }
INIT
export BCOUT=3 BCIN=4 BCPID="$!"
... đó là phần khó khăn. Và đây là phần thú vị ...
set --
until [ "$#" -eq 10 ]
do printf '%s()\n' b c a >&"$BCIN"
set "$@" "$(head -n 3 <&"$BCOUT")"
done; printf %s\\n "$@"
... mà in ...
b=3
c=.14112000805986722210
a=1.14112000805986722210
#...24 more lines...
b=3.92307618030433853649
c=-.70433330413228041035
a=.29566669586771958965
... và nó vẫn đang chạy ...
echo a >&"$BCIN"
read a <&"$BCOUT"
echo "$a"
... mà chỉ được cho tôi những giá trị cuối cùng cho bc
's a
thay vì gọi các a()
chức năng để tăng nó và in ...
.29566669586771958965
Trên thực tế, nó sẽ tiếp tục chạy cho đến khi tôi giết nó và phá vỡ các đường ống IPC của nó ...
kill "$BCPID"; exec 3>&- 4>&-
unset BCPID BCIN BCOUT