【问题标题】:Writing from multiple processes launched via xargs to the same fifo pipe causes lines to miss从通过 xargs 启动的多个进程写入同一个 fifo 管道会导致行丢失
【发布时间】:2020-11-08 21:14:28
【问题描述】:

我有一个脚本,我可以在其中并行执行作业,同时监控进度。我使用xargs 和一个命名的fifo 管道来做到这一点。我的问题是,虽然xargs 表现良好,但写入管道的一些行丢失了。 知道问题出在哪里吗?

例如以下脚本(基本上是我的带有虚拟数据的脚本)将产生以下输出并在最后挂起等待那些缺失的行:

$ bash test2.sh 
Progress: 0 of 99
DEBUG: Processed data 0 in separate process
Progress: 1 of 99
DEBUG: Processed data 1 in separate process
Progress: 2 of 99
DEBUG: Processed data 2 in separate process
Progress: 3 of 99
DEBUG: Processed data 3 in separate process
Progress: 4 of 99
DEBUG: Processed data 4 in separate process
Progress: 5 of 99
DEBUG: Processed data 5 in separate process
DEBUG: Processed data 6 in separate process
DEBUG: Processed data 7 in separate process
DEBUG: Processed data 8 in separate process
Progress: 6 of 99
DEBUG: Processed data 9 in separate process
Progress: 7 of 99
##### Script is hanging here (Could happen for any line) #####
#!/bin/bash
clear

printStateInLoop() {
  local pipe="$1"
  local total="$2"
  local finished=0

  echo "Progress: $finished of $total"
  while true; do
    if [ $finished -ge $total ]; then
      break
    fi

    let finished++
    read line <"$pipe"
      # In final script I would need to do more than just logging
    echo "Progress: $finished of $total"
  done
}

processData() {
  local number=$1
  local pipe=$2

  sleep 1 # Work needs time
  echo "$number" >"$pipe"
  echo "DEBUG: Processed data $number in separate process"
}
export -f processData

process() {
  TMP_DIR=$(mktemp -d)
  PROGRESS_PIPE="$TMP_DIR/progress-pipe"
  mkfifo "$PROGRESS_PIPE"

  DATA_VECTOR=($(seq 0 1 99)) # A bunch of data
  printf '%s\0' "${DATA_VECTOR[@]}" | xargs -0 --max-args=1 --max-procs=5 -I {} bash -c "processData \$@ \"$PROGRESS_PIPE\"" _ {} &

  printStateInLoop "$PROGRESS_PIPE" ${#DATA_VECTOR[@]}
}

process
rm -Rf "$TMP_DIR"

another post 中,我收到了切换到while read line; do … done &lt; "$pipe"(下面的函数)而不是while true; do … read line &lt; "$pipe" … done 的建议,以便不要在读取的每一行时关闭管道。这降低了问题的频率,但它仍然会发生:缺少某些行,有时会出现xargs: bash: terminated by signal 13

printStateInLoop() {
  local pipe="$1"
  local total="$2"
  local finished=0

  echo "Progress: $finished of $total"
  while [ $finished -lt $total ]; do
    while read line; do
      let finished++
      # In final script I would need to do more than just logging
      echo "Progress: $finished of $total"
    done <"$pipe"
  done
}

SO 上的很多人建议使用 parallelpv 来执行此操作。遗憾的是,这些工具在非常有限的目标平台上不可用。相反,我的脚本基于xargs

【问题讨论】:

  • 您是否考虑过让每个写入者在写入管道之前获得管道上的锁?在bash linux flock write pipe 上的谷歌搜索带来了一些提示,包括对FIFO with single READER and multiple WRITERS in BASH 的一个有希望的答案
  • 对管道的写入没有互锁。很可能的事件将被覆盖。也许您需要互锁进程(群?)。或者将每个写入单独的管道并收集结果
  • 谢谢。这确实解决了问题。我已经搜索过文件锁定机制,但显然没有使用正确的搜索词。

标签: bash shell concurrency xargs mkfifo


【解决方案1】:

解决方案(正如@markp-fuso 和@Dale 指出的那样)是创建文件锁。

代替:

echo "$number" >"$pipe"

我现在使用flock首先创建/等待锁:

flock "$pipe.lock" echo "$number" >"$pipe"

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-08
    • 1970-01-01
    • 2018-02-09
    相关资源
    最近更新 更多