Bash 命名管道 - 原子读取

Bash 命名管道 - 原子读取

我设置了一个脚本来写入命名管道,然后设置了四个脚本来读取命名管道。

对于大多数条目来说,没有问题,但是当对输入行进行很少的处理时,一些读取开始相互冲突,并且生成的文本是随机字符的组合(最多) 4 行用于(最多)4 个进程。

我无法使用 xargs 或并行的原因是,与数据库的连接时间需要 1 秒,加起来通常有大约 1300 行需要处理。

示例输出:

在 1 秒内完成 MAIN.MK37 上的 Runstats:DB20000I RUNSTATS 命令成功完成。

在 0 秒内完成 MAIN.MKAP 上的 Runstats:DB20000I RUNSTATS 命令成功完成。

在 0 秒内完成 MAIN.MKAL 上的 Runstats:DB20000I RUNSTATS 命令成功完成。

在 0 秒内完成 MAIN.MK49 上的 Runstats:DB20000I RUNSTATS 命令成功完成。

0 秒后 AI.K1MAIN 上的运行统计失败: SQL2306N 表或索引“AI.K1MAIN”不存在。

MNM5 上的 Runstat 失败。 0 后:SQL0104N 意外的标记“MNM5”。是在“TBLE”之后找到的。预期的标记可能包括:“”。 SQL状态=42601

在 0 秒内完成 MAIN.MK50 上的 Runstats:DB20000I RUNSTATS 命令成功完成。

在 0 秒内完成 MAIN.MK52 上的 Runstats:DB20000I RUNSTATS 命令成功完成。

作家:

# Open pipe for writing
exec 10>"${PIPE_LOCATION}"

# Feed data
while read LINE; do
    echo "${LINE}" >&10
done <<< "${LIST}"

# Tell threads to stop
i=0
while [ "${i}" -lt 4 ]; do
    echo "stop" >&10
    (( i += 1 ))
done

# Close pipe
exec 10>&-

读者:

# Open Pipe
exec 10<"${PIPE_LOCATION}"

while read -u 10 -r SCHEMA TABLE; do
    if [[ "${SCHEMA}" == 'stop' ]]; then
        break
    fi

    #
    # Runstats Code Here
    #

done

# Close Pipe
exec 10<&-

有什么方法可以使读取原子化吗?

我想我可以像服务器一样协调主线程,并且四个读者每次需要一些输入时都可以向它发送一个请求,这可能会解决问题(不过,是 5 个管道而不是 1 个!),但是如果有一个有人可以建议更简单的解决方案,我洗耳恭听!

答案1

@MarkPlotnick 有正确的想法。我更改了脚本以用空格填充行并使用固定大小的记录进行读取。

注意:根据 @Hauke Laging 的发现,文件描述符现在是 5 而不是 10

我现在像这样提供数据:

# Feed data
while read LINE; do
    printf "%64s" "${LINE}" >&5
done <<< "${LIST}"

像这样读:

while read -u 5 -N 64 -r LINE; do
    LINE=(${LINE})
    SCHEMA=${LINE[0]}
    TABLE=${LINE[1]}

并且不再有错误!

相关内容