首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >通过xargs显式排序并行化- xargs的不完全结果

通过xargs显式排序并行化- xargs的不完全结果
EN

Stack Overflow用户
提问于 2015-08-10 18:48:14
回答 1查看 461关注 0票数 1

上下文

我需要使用‘排序-u’优化去重复,我的linux机器有一个旧的‘排序’命令实现(即5.97),没有‘-并行’选项。虽然“排序”实现了可并行的算法(例如合并排序),但我需要使这种并行化显式化。因此,我是通过'xargs‘命令手工完成的,它的性能超过了~2.5xw.r.t。单一的“排序-u”方法..。当它正常工作的时候。

这里是我所做的事情的直觉。

我正在运行一个bash脚本,它将输入文件(例如file.txt)分成几个部分(例如file.txt.part1、file.txt.part2、file.txt.part3、file.txt.part4)。生成的部分被传递给'xargs‘命令,以便通过sortu.sh脚本执行并行去重复(后面是详细信息)。sortu.sh封装对'sort -u‘的调用并输出结果文件名(例如,"sortu.sh file.txt.part1“输出”file.txt.part1.order“)。然后,得到的排序部分被传递给一个“排序--合并-u”,它合并/重复输入部分,前提是这些部分已经排序。

我正在经历的问题是通过'xargs‘进行并行化。这里是我的代码的简化版本:

代码语言:javascript
复制
 AVAILABLE_CORES=4
 PARTS="file.txt.part1
 file.txt.part2
 file.txt.part3
 file.txt.part4"

 SORTED_PARTS=$(echo "$PARTS" | xargs --max-args=1 \
                                      --max-procs=$AVAILABLE_CORES \
                                      bash sortu.sh \
               )
 ...
 #More code for merging the resulting parts $SORTED_PARTS
 ...

期望的结果是将部分排序到变量SORTED_PARTS中的列表:

代码语言:javascript
复制
 echo "$SORTED_PARTS"
 file.txt.part1.sorted
 file.txt.part2.sorted
 file.txt.part3.sorted
 file.txt.part4.sorted

症状

尽管如此,(有时)还是有一个缺失的排序部分。例如,file.txt.part2.排序如下:

代码语言:javascript
复制
 echo "$SORTED_PARTS"
 file.txt.part1.sorted
 file.txt.part3.sorted
 file.txt.part4.sorted

这个症状在它的出现(即对同一个file.txt的执行成功,在另一个时间它失败)或在缺少的文件中(也就是说,它并不总是相同的排序缺失部分)中是不确定的。

问题

我有一个种族条件,所有的sortu.sh实例都完成了,'xargs‘在stdout被刷新之前发送EOF。

问题

在“xagrs”发送EOF之前,是否有办法确保stdout冲洗?

约束

我既不能使用平行命令,也不能使用排序命令的“-并行”选项。

sortu.sh代码

代码语言:javascript
复制
 #!/bin/bash

 SORTED=$1.sorted
 sort -u $1 > $SORTED
 echo $SORTED
EN

回答 1

Stack Overflow用户

发布于 2015-08-11 16:04:12

下面的代码根本没有将内容写入磁盘,而是并行化拆分进程、排序进程和合并,同时执行所有这些操作。

这个版本已经移植到bash3.2;为更新版本bash构建的版本不需要eval

代码语言:javascript
复制
#!/bin/bash

nprocs=5  # maybe call nprocs command instead?
fd_min=10 # on bash 4.1, can use automatic FD allocation instead

# create a temporary directory; delete on exit
tempdir=$(mktemp -d "${TMPDIR:-/tmp}/psort.XXXXXX")
trap 'rm -rf "$tempdir"' 0

# close extra FDs and clear traps, before optionally executing another tool.
#
# Doing this in subshells ensures that only the main process holds write handles on the
# individual sorts, so that they exit when those handles are closed.
cloexec() {
    local fifo_fd
    for ((fifo_fd=fd_min; fifo_fd < (fd_min+nprocs); fifo_fd++)); do
        : "Closing fd $fifo_fd"
        # in modern bash; just: exec {fifo_fd}>&-
        eval "exec ${fifo_fd}>&-"
    done
    if (( $# )); then
        trap - 0
        exec "$@"
    fi
}

# For each parallel process:
# - Run a sort -u invocation reading from an FD and writing from a FIFO
# - Add the FIFO's name to a merge sort command
merge_cmd=(sort --merge -u)
for ((i=0; i<nprocs; i++)); do
  mkfifo "$tempdir/fifo.$i"               # create FIFO
  merge_cmd+=( "$tempdir/fifo.$i" )       # add to sort command line
  fifo_fd=$((fd_min+i))
  : "Opening FD $fifo_fd for sort to $tempdir/fifo.$i"
  # in modern bash: exec {fifo_fd}> >(cloexec sort -u >$fifo_fd)
  printf -v exec_str 'exec %q> >(cloexec; exec sort -u >%q)' "$fifo_fd" "$tempdir/fifo.$i"
  eval "$exec_str"
done

# Run the big merge sort recombining output from all the FIFOs
cloexec "${merge_cmd[@]}" &
merge_pid=$!

# Split input stream out to all the individual sort processes...
awk -v "nprocs=$nprocs" \
    -v "fd_min=$fd_min" \
  '{ print $0 >("/dev/fd/" (fd_min + (NR % nprocs))) }'

# ...when done, close handles on the FIFOs, so their sort invocations exit
cloexec

# ...and wait for the merge sort to exit
wait "$merge_pid"
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31926950

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档