我的文本文件很大(1.5 G),
我想知道Linux中最快,更可靠的工具是什么。
我通常使用:
awk '!x[$0]++' file.txt
但是当我使用htop
命令时,我看到我的内存使用量正在增加。
我想知道什么是处理大型文件最快,更可靠的方法。
uniq?
sort?
sed?
awk?
为什么?
我的文本文件很大(1.5 G),
我想知道Linux中最快,更可靠的工具是什么。
我通常使用:
awk '!x[$0]++' file.txt
但是当我使用htop
命令时,我看到我的内存使用量正在增加。
我想知道什么是处理大型文件最快,更可靠的方法。
uniq?
sort?
sed?
awk?
为什么?
Answers:
让我们考虑每个解决方案的工作方式。
uniq
这要求文件已被排序。如果不是,则必须sort
先将其通过管道传输,这意味着sort
必须将整个文件读入内存,对其重新排序(O(n log n)
),然后将其写入管道。的工作uniq
非常便宜,因为它只需要比较其输入的相邻行。
sort -u
这结合了的工作sort | uniq
。这必须像awk
脚本一样将所有唯一的输入收集到内存中,但是在生成输出之前,还要浪费时间对它们进行排序。这是O(n log n)
,尽管在这种情况下n
是唯一项目的数量,而不是所有输入。因此,它比管道更好。
sed
我不确定您为什么列出此内容,因为我根本想不出一种很好的方法来完成此操作sed
。也许,如果您首先对其进行排序并通过管道传递给sed
脚本,那么就有一种比较相邻行的方法。因此,sed
将只做某事uniq
,并且uniq
可能会尽可能高效地完成它。
awk
这可能是最好的,因为它仅执行最少的工作量。在读取每一行时,它会进行有效的哈希查找,以查看该行是否已在其内存中,并且仅将唯一行存储为哈希键,并将计数器存储为值。(如果该行以前不存在,则条件为true,因此将打印该行。否则将不会打印。)这会占用O(n)
时间和O(uniq n)
内存。
每种方法都将使用大量内存,用于对输入进行排序或跟踪已看到的输入,以便删除重复项。
awk
还解释了为什么它使用越来越多的内存。任何进行排序的操作最终也会执行此操作,只有1)它可能会一次全部使用,2)它可能会使用更多,这取决于唯一键与重复键的数量。
sort
以一种智能的方式求助于临时文件,以避免填满内存。它的内存使用率是有约束的。该边界可通过某种实现方式进行自定义。让系统将内存随机交换到磁盘(这也会影响系统上的应用程序),效率更高。
awk
内存不足的情况,则sort
可能是唯一的解决方案,因为它已被设计用来处理此问题。另一方面,所有磁盘读取和写入操作都会减慢其速度,因此可能需要很长时间才能完成。如果要处理大量数据,则可能应该使用DBMS而不是文本文件。
O(n log n)
?还是您从其他地方知道?
我发现排序似乎是最快的uniq工具,如下所示-> 删除大型单词列表中重复项的最快方法?
我只是想指出uniq
,即使在排序列表上,gnu 似乎也非常慢。
我只是尝试从排序的文件名列表中获取目录前缀列表:
$ pv all_files | cut -d '/' -f 1,2,3,4 | uniq > all_prefixes
36.7GiB 0:07:41 [81.4MiB/s]
$ pv all_files | cut -d '/' -f 1,2,3,4 | sort -u > all_prefixes2
36.7GiB 0:03:14 [ 193MiB/s]
$ pv all_files | cut -d '/' -f 1,2,3,4 | awk '!x[$0]++' > all_prefixes3
36.7GiB 0:02:18 [ 270MiB/s]
sort -u似乎是uniq的两倍,这是从stdin读取并写入stdout的排序,所以我还没有看到它进行任何并行化。我不知道为什么uniq应该这么慢然后排序,因为它不必对列表进行排序...
该命令的输出非常小(有很多重复项),只有264kb,并且pv完成后排序会立即终止。
如果改变命令的顺序,速度将保持不变,我的流量在这里受CPU时间的限制,而不是磁盘访问和缓存的限制(我只有8GB的RAM,未使用交换空间)
我在具有gnu coreutils sort和uniq和gnu awk的fedora 31机器上运行该代码;语言环境设置为en_US.UTF-8
UPDATE,因为这引起了我的极大兴趣,所以我进行了一些更多的测试,让我们将剪切的部分排除在外,并确保文件排序正确
cat all_files | cut -d '/' -f 1,2,3,4 | sort -T . > test
这需要8.4分钟。测试现在是7.9GB大
让我们在文件上而不是在管道上运行这些工具,这将允许这些工具做更多的优化,例如sort将是多线程的。以及更快的ssd。
您可能不会注意到排序也占用了大量内存,因为它会对/ tmp中的临时文件(可能是tmpfs并在您的ram中)进行巧妙的欺骗(尝试对大于/ tmp的文件进行排序,您会遇到空间问题问题,这就是为什么我需要上述命令中的-T。标志)
$ time sort -u test > /dev/null
339.24user 3.54system 1:28.87elapsed 385%CPU (0avgtext+0avgdata 2365856maxresident)k
9555544inputs+0outputs (0major+591298minor)pagefaults 0swaps
$ time awk '!x[$0]++' test > /dev/null
51.15user 1.55system 0:52.94elapsed 99%CPU (0avgtext+0avgdata 10976maxresident)k
0inputs+0outputs (0major+1923minor)pagefaults 0swaps
$ time uniq test > /dev/null
421.89user 2.76system 7:06.63elapsed 99%CPU (0avgtext+0avgdata 1980maxresident)k
52712inputs+0outputs (0major+79minor)pagefaults 0swaps
因此,看来您的awk解决方案是这3种解决方案中最快的,并且实际上使用的内存最少
update2 ,现在具有更简单的语言环境
$ export LC_ALL=c
$ time sort -u test > /dev/null 1.2m ? Tue Apr 21 17:09:22 2020
119.18user 3.64system 0:38.24elapsed 321%CPU (0avgtext+0avgdata 2013472maxresident)k
$ time awk '!x[$0]++' test > /dev/null 1161ms ? Tue Apr 21 17:07:31 2020
67.23user 2.50system 1:10.16elapsed 99%CPU (0avgtext+0avgdata 10480maxresident)k
7187520inputs+0outputs (0major+1912minor)pagefaults 0swaps
$ time uniq test > /dev/null
22.05user 2.02system 0:24.24elapsed 99%CPU (0avgtext+0avgdata 1488maxresident)k
2959648inputs+0outputs (1major+72minor)pagefaults 0swaps
这次uniq确实赢得了比赛 ...正如StéphaneChazelas在评论中暗示的那样,将您的语言环境设置为C可以使sort和uniq更快!
sort
和执行什么uniq
?什么地区?
time
?