如何为 shell 任务创建有界队列?

如何为 shell 任务创建有界队列?

我有 1000 个 gzip 压缩文件想要排序。

按顺序执行此操作,过程看起来非常简单:

find . -name *.gz -exec zcat {} | sort > {}.txt \;

不确定上面的代码是否有效(如果我在某个地方犯了错误,请纠正我),但我希望你理解这个想法。

不管怎样,我想并行化 ungzip/sort 作业以使整个过程更快。另外,我不希望看到所有 1000 个进程同时运行。如果有一些具有可配置容量的有界作业队列(例如 Java 中的 BlockingQueue 或 .NET 中的 BlockingCollection),那就太好了。在这种情况下,只有 10 个进程会并行运行。

可以在 shell 中执行此操作吗?

答案1

使用 GNU 并行:

find . -name *.gz | parallel --files 'zcat {} | sort' | parallel -X -j1 sort -m {} ';' rm {} > sorted

您可以简单地通过以下方式安装 GNU Parallel:

wget http://git.savannah.gnu.org/cgit/parallel.git/plain/src/parallel
chmod 755 parallel

观看介绍视频以了解更多信息:https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1并浏览本教程 (man parallel_tutorial)。你非常喜欢命令行。

答案2

我会选择make(1)这个任务——它不是 shell,但是make(1)jobserver 几乎正是您想要的,并且这个任务非常适合 的make(1)能力。请注意,行开头gzip -cd以制表符缩进。这一点至关重要。 (make(1)有时也会感觉有点老了。)

$ cat Makefile 
TXT := $(wildcard *.gz)

all: $(TXT:.gz=.txt)

%.txt:%.gz
    gzip -cd $< | sort > $@
$ cp /usr/share/man/man2/*.gz .
$ ls -l
total 1992
-rw-r--r-- 1 sarnold sarnold  4447 2011-12-06 00:22 aa_change_hat.2.gz
-rw-r--r-- 1 sarnold sarnold  3977 2011-12-06 00:22 aa_change_profile.2.gz
-rw-r--r-- 1 sarnold sarnold  5082 2011-12-06 00:22 accept.2.gz
...
$ time make -j 10
gzip -cd aa_change_hat.2.gz | sort > aa_change_hat.2.txt
gzip -cd aa_change_profile.2.gz | sort > aa_change_profile.2.txt
gzip -cd accept.2.gz | sort > accept.2.txt
gzip -cd accept4.2.gz | sort > accept4.2.txt
gzip -cd access.2.gz | sort > access.2.txt
...
gzip -cd write.2.gz | sort > write.2.txt
gzip -cd writev.2.gz | sort > writev.2.txt

real    0m0.259s
user    0m0.190s
sys 0m0.020s
$ rm w*txt
$ make
gzip -cd wait.2.gz | sort > wait.2.txt
gzip -cd wait3.2.gz | sort > wait3.2.txt
gzip -cd wait4.2.gz | sort > wait4.2.txt
gzip -cd waitid.2.gz | sort > waitid.2.txt
gzip -cd waitpid.2.gz | sort > waitpid.2.txt
gzip -cd write.2.gz | sort > write.2.txt
gzip -cd writev.2.gz | sort > writev.2.txt
$ 

请注意rm w*txt,该命令make(1)仅智能地执行完成任务所需的最少工作量。

答案3

快速浏览一下 Google 就会发现这种有趣的方法:http://pebblesinthesand.wordpress.com/2008/05/22/a-srcipt-for-running-processes-in-parallel-in-bash/

for ARG in  $*; do
    command $ARG &
    NPROC=$(($NPROC+1))
    if [ "$NPROC" -ge 4 ]; then
        wait
        NPROC=0
    fi
done

答案4

使用 GNU xargs,您可以执行以下操作:

xargs -P4 -n 10 -r0a <(find . -name '*.gz' -type f -print0) sh -c '
  for file do
    zcat < "$file" | sort > "$file.txt"
  done' sh {} +

这将并行调用最多 4 个文件sh,每个文件在一个循环中依次处理最多 10 个文件。

相关内容