我正在尝试使用 egrep 和 sort -u 从一个文件中提取一组行,然后对它们进行计数。大约 10% 的行(所有 100 个字符长的字母表 [ATCG])是重复的。有两个文件,每个文件大约 3 GB,50% 不相关,所以可能有 3 亿行。
LC_ALL=C grep -E <files> | sort --parallel=24 -u | wc -m
在 LC_ALL=C 和使用 -x 加速 grep 之间,到目前为止最慢的部分是排序。阅读手册页让我想到了 --parallel=n,但实验表明没有任何改善。使用 top 进行一些挖掘表明,即使使用 --parallel=24,排序过程也只能在一个处理器上运行。
我有 4 个芯片,每个芯片有 6 个内核,每个内核有 2 个线程,总共有 48 个逻辑处理器。请参阅 lscpu,因为 /proc/cpuinfo 太长了。
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 48
On-line CPU(s) list: 0-47
Thread(s) per core: 2
Core(s) per socket: 6
Socket(s): 4
NUMA node(s): 8
Vendor ID: AuthenticAMD
CPU family: 21
Model: 1
Stepping: 2
CPU MHz: 1400.000
BogoMIPS: 5199.96
我遗漏了什么?即使该过程是 IO 密集型的,难道我不应该看到并行处理吗?排序过程在任何给定时间都使用了它实际使用的处理器的 99%,因此如果发生并行化,我应该能够看到它。内存不是问题,我有 256 Gb 可以玩,而且没有任何东西使用它。
我发现将 grep 传输到一个文件,然后使用 sort 读取该文件:
LC_ALL=C grep -E <files> > reads.txt ; sort reads.txt -u | wc -m
default, file 1m 50s
--parallel=24, file 1m15s
--parallel=48, file 1m6s
--parallel=1, no file 10m53s
--parallel=2, no file 10m42s
--parallel=4 no file 10m56s
others still running
在进行这些基准测试时,很明显,当管道输入时,排序根本不并行。当允许读取文件时,排序会按指示拆分负载。
答案1
sort 不会在需要时创建线程,而对于小文件来说,这实在是太过繁琐了。现在不幸的是,sort 将管道视为小文件。如果您想要向 24 个线程提供足够的数据,那么您需要指定 sort 使用大型内部缓冲区(sort 在处理大文件时会自动执行此操作)。这是我们应该在上游改进的地方(至少在文档中)。因此,您需要类似以下内容:
(export LC_ALL=C; grep -E <files> | sort -S1G --parallel=24 -u | wc -m)
注意,我为所有进程设置了 LC_ALL=C,因为它们都将受益于这些数据)。
顺便说一句,你可以用类似下面的方法监视排序线程:
watch -n.1 ps -C sort -L -o pcpu
答案2
您parsort
可以在多核机器上更快地对大文件进行排序。
在 48 核机器上,您应该看到排序速度提高了 3 倍。
parsort
是 GNU Parallel 的一部分并且应该是 的替代品sort
。