Linuxで最速の `uniq`ツール


8

大きなテキストファイル(1.5 G)があります。

Linuxで最も高速で信頼性の高いツールを教えてください。

私は通常使用します:

awk '!x[$0]++' file.txt

しかし、htopコマンドを使用すると、メモリ使用量が増加していることがわかります。

巨大なファイルで最も速くて信頼性の高いものを知りたい。

uniq?
sort?
sed?
awk?

どうして?


それらを実行してみましたtimeか?
チョロバ2014年

時間は重要であり、メモリの使用量と信頼性も重要です(つまり、彼が正確に仕事をしていることを意味します)
MLSC 2014年

まだ...しかし、私は以前にいくつかのテストを行いました...そしてどこかで尋ねました、いくつかの人はawkが最高だと言いました...しかし、htopでは...メモリ使用量が増加しているようです
MLSC

3
@MortezaLSC:それはトレードオフです。プログラムが高速であるほど、より多くのメモリが使用されます。
cuonglm 14年

回答:


16

各ソリューションがどのように機能するかを考えてみましょう。

  • 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)メモリを使用します。

すべてのメソッドは、入力をソートするため、または重複を削除できるように、どの入力が表示されたかを追跡するためにかなりの量のメモリを使用します。


1
+1に関するawk説明では、メモリの使用量が増える理由も説明されています。並べ替えを行うものはすべてこれも行うことになり、1)おそらく一度にすべてを使用します。2)一意のキーと重複するキーの数に応じて、わずかに多く使用します。
goldilocks 2014年

@Barmarの恩赦ですが、メモリ容量が8Gの大きなファイル(16 G)がある場合、私のメモリはどうなりますか?
MLSC 2014年

8
@goldilocks、sort一時的なファイルを使用して(インテリジェントな方法で)、メモリがいっぱいにならないようにします。そのメモリ使用量は制限されています。境界は、いくつかのソート実装でカスタマイズ可能です。システムにメモリをランダムにディスクにスワップさせる(システム上のアプリケーションにも影響する)よりも効率的です。
ステファンChazelas

それは本当だ。したがってawk、メモリが不足するケースに遭遇した場合はsort、これに対処するように設計されているため、唯一の解決策になる可能性があります。一方、ディスクの読み取りと書き込みはすべて速度が低下するため、完了するまでに時間がかかる可能性があります。このような大量のデータを扱う場合は、テキストファイルではなくDBMSを使用しているはずです。
Barmar

@Barmar再注文の時間が増えるにつれて、どのように推測されましたO(n log n)か?それとも他の場所から知っているだけですか?
jimmij 2014年


0

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の2倍の速度で表示されます。これは、stdinからのsortの読み取りとstdoutへの書き込みで行われるため、並列化はまだ行われていません。リストをソートする必要がないので、なぜuniqがソートよりもはるかに遅くなるのか私にはわかりません...

このコマンドのoutpufは非常に小さく(多くの重複があります)、264kbのみで、pvが実行された直後にソートが終了します。

コマンドの順序を変えても同じ速度が維持されます。ここでのフローは、ディスクアクセスやキャッシュではなく、ここでのCPU時間によって制限されます(RAMは8 GBしかなく、スワップは使用されていません)。

私はこれを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になりました

パイプではなくファイルでこれらのツールを実行してみましょう。これにより、これらのツールは、並べ替えがマルチスレッドのようにさらに最適化できます。また、より高速なssdから。

/ tmpにある一時ファイルで巧妙なトリックを実行しているため、sortも大量のメモリを使用していることに気付かないかもしれません。問題、それが上記のコマンドで-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に設定すると、並べ替えとuniqがかなり速くなります!


どのような実装sortuniq?どのロケール?
ステファンChazelas
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.