是否可以有多个并发协进程?

是否可以有多个并发协进程?

意图下面的测试脚本1的目的是启动一个“外部”协进程(正在运行seq 3),在循环中从此协进程读取数据while,并且对于读取的每一行,打印一行标识外部循环的当前迭代,启动“内部” coprocess(也在运行seq,带有新参数),在嵌套的 while 循环中读取此内部协进程,然后清理此内部协进程。嵌套的 while 循环为它从内部协进程读取的每一行打印一些输出。

#!/bin/bash
# filename: coproctest.sh
PATH=/bin:/usr/bin

coproc OUTER { seq 3; }
SAVED_OUTER_PID="${OUTER_PID}"

exec {OUTER_READER}<&"${OUTER[0]}"
while IFS= read -r -u "${OUTER_READER}" OUTER_INDEX; do

    printf -- '%d\n' "${OUTER_INDEX}"

    START=$(( OUTER_INDEX * 1000000 ))
    FINISH=$(( START + OUTER_INDEX ))

    # (
      coproc INNER { seq "${START}" "${FINISH}"; }
      SAVED_INNER_PID="${INNER_PID}"
      exec {INNER_READER}<&"{INNER[0]}"

      while IFS= read -r -u "${INNER_READER}" INNER_INDEX; do
          printf -- '    %d\n' "${INNER_INDEX}"
      done

      exec {INNER_READER}<&-

      wait "${SAVED_INNER_PID}"
    # )

done
exec {OUTER_READER}<&-
wait "${SAVED_OUTER_PID}"

当我运行此脚本时,这是我得到的输出:

% ./coproctest.sh
1
./coproctest.sh: line 30: warning: execute_coproc: coproc [12523:OUTER] still exists
./coproctest.sh: line 19: INNER_READER: ambiguous redirect
./coproctest.sh: line 21: read: : invalid file descriptor specification
./coproctest.sh: line 25: INNER_READER: ambiguous redirect
2
./coproctest.sh: line 19: INNER_READER: ambiguous redirect
./coproctest.sh: line 21: read: : invalid file descriptor specification
./coproctest.sh: line 25: INNER_READER: ambiguous redirect
3
./coproctest.sh: line 19: INNER_READER: ambiguous redirect
./coproctest.sh: line 21: read: : invalid file descriptor specification
./coproctest.sh: line 25: INNER_READER: ambiguous redirect

如果取消注释两行注释,我会得到几乎相同的输出。


问题一:是否可以同时运行多个协进程?

问题2:如果是这样,应该如何修改上面的脚本以获得所需的输出?


1我最近才开始使用协进程,还有很多不明白的地方。因此,该脚本几乎肯定包含不正确、笨拙或不必要的代码。请随时评论和/或修复您的回复中的这些弱点。

答案1

从手册最后的“BUGS”部分bash

一次可能只有一个活动协进程。

答案2

Q1:是否可以同时运行多个协进程?

在 Bash v4 及更高版本(包括当前的 v5)上,官方没有,正如 @Kusalananda 所指出的。

不过,我可以告诉你,它可能尽管有警告,但工作当然没有保证和YMMV。看这里以获得更多见解。

Q2:如果是这样,上面的脚本应该如何修改才能达到预期的输出?

可能(如上所述)一旦修复以下问题就可以正常工作:

exec {INNER_READER}<&"{INNER[0]}"  # <-- lacks the '$' sign for the 'INNER[0]' variable

这会导致:

./coproctest.sh: line 19: INNER_READER: ambiguous redirect

消息,因此还有:

./coproctest.sh: line 21: read: : invalid file descriptor specification

信息。

它对我有用,一旦解决了这个问题并抛开警告。

至于其他注意事项:

  • 不需要重复 acoproc的文件描述符,除非您想将它们传递给子进程(子 shell 或命令或脚本)
  • 您这样做可能是因为该seq命令自然会很快完成,因此自动变量在您可以使用它们之前就消失了。通过按照您的方式进行,这些重复的文件描述符将被所有后续命令和后台进程继承,如果您的协进程实际上使用其输入管道并等待其关闭才能退出,这可能是不可取的。因此,解决这个问题的另一种方法是通过同步机制,例如让您的OUTER协进程成为{ seq 3; exec >&-; read; },然后当您消耗了主脚本的输入时,echo >&${OUTER[1]}; wait "${OUTER_PID}"让协进程read继续进行wait。请注意,不能保证将在变量消失wait之前执行$OUTER_PID:在这种情况下,您可以将警告消息静音(或完全忽略它),并可能使用|| true
  • 作为个人旁注,我可以告诉您,如果您确实决心同时进行多个协同进程,您可能会重新实现粗糙的相当于coproc在后台进程上使用 Bash v3 语法加上mkfifo命名 FIFO,并且在 Linux 上还使用进程替换而不是mkfifos 的技巧。使用 Bash v4 语法,它可以不那么复杂,但仍然是一个具有挑战性的练习。

相关内容