是否可以通过 GNU 并行化 awk 写入多个文件?

Is it possible to parallelize awk writing to multiple files through GNU parallel?

我是 运行 我想通过 GNU parallel 并行化的 awk 脚本。

此脚本根据每一行的值将一个输入文件多路分解为多个输出文件。代码如下:

#!/usr/bin/awk -f

BEGIN{ FS=OFS="\t" }
{
    # bc is the field that defines to which file the line
    # will be written
    bc = 
    # append line to such file
    print >> (bc".txt")
}

我想通过以下方式使用 GNU parallel 对其进行并行化:

parallel --line-buffer --block 1G --pipe 'awk script.awk'

但是,我担心两个 awk 进程同时写入同一个文件可能会出现竞争情况。是否可能,如果是,如何在不影响并行化的情况下避免它?

注意。我包含了 --line-buffer 选项,尽管我不确定它是否也适用于 awk 脚本中的文件重定向。它是否也适用于这种情况或仅适用于每个 awk 进程的标准输出?

例子

# Input file
bc1    line1
bc3    line2
bc1    line3
bc2    line4


# Output file bc1.txt
bc1    line1
bc1    line3

# Output file bc2.txt
bc2    line4

# Output file bc3.txt
bc3    line2

你可以通过多路分解不同目录中的输出来做到这一点:

stuff |
  parallel --block 10M --pipe --round-robin \
    'mkdir -p dir-{%}; cd dir-{%}; awk ../script.awk'

或者如果输入是一个文件,你可以使用 --pipepart 哪个更快:

parallel --block -1 --pipepart -a bigfile \
  'mkdir -p dir-{%}; cd dir-{%}; awk ../script.awk'

那就没有竞争条件了。通过合并目录完成:

parallel 'cd {}; ls' ::: dir-* | sort -u |
  parallel 'cat */{} > {}'

如果不能合并(可能你没有磁盘space 2份数据),你可以使用fifos。但要做到这一点,您需要提前知道所有 .txt 文件的名称,并且您需要一个系统可以 运行 每个名称并行一个进程(10000 个名称 = 10000 个进程):

# Generate names-of-files.txt somehow
# Make fifos for all names in all slots
parallel 'mkdir -p {2}; mkfifo {2}/{1}' :::: \
  names-of-files.txt <(seq $(parallel --number-of-threads) )
# Run the demultiplexer in the background
parallel --block -1 --pipepart -a bigfile \
  'mkdir -p dir-{%}; cd dir-{%}; awk ../script.awk' &
# Start one process per name
# If you have more than 32000 names, you will need to increase the number
# of processes on your system.
cat names-of-files.txt |
  parallel -j0 --pipe -N250 -I ,, parallel -j0 'parcat */{} > {}'