Pythonのset
およびfrozenset
コレクション型をいじっていました。
最初は、frozenset
は不変であるため、set
よりも優れたルックアップパフォーマンスを提供し、したがって格納されたアイテムの構造を活用できると想定しました。
ただし、次の実験に関してはそうではないようです。
import random
import time
import sys
def main(n):
numbers = []
for _ in xrange(n):
numbers.append(random.randint(0, sys.maxint))
set_ = set(numbers)
frozenset_ = frozenset(set_)
start = time.time()
for number in numbers:
number in set_
set_duration = time.time() - start
start = time.time()
for number in numbers:
number in frozenset_
frozenset_duration = time.time() - start
print "set : %.3f" % set_duration
print "frozenset: %.3f" % frozenset_duration
if __name__ == "__main__":
n = int(sys.argv[1])
main(n)
CPythonとPyPyの両方を使用してこのコードを実行すると、次の結果が得られました。
> pypy set.py 100000000
set : 6.156
frozenset: 6.166
> python set.py 100000000
set : 16.824
frozenset: 17.248
frozenset
は、CPythonとPyPyの両方で、ルックアップのパフォーマンスに関して実際には遅いようです。なぜこれが当てはまるのか誰にも分かりますか?私は実装を調査しませんでした。
frozenset
とset
の実装は大部分が共有されています。 set
は、変更メソッドが追加された単純なfrozenset
であり、まったく同じハッシュテーブル実装です。 Objects/setobject.c
ソースファイル ;トップレベル PyFrozenSet_Type
定義 関数を PySet_Type
定義 。
ここでは、アイテムのハッシュを計算する必要がないため、frozensetの最適化はありませんinfrozenset
メンバーシップのテスト。セットのテストに使用するアイテムagainstセットのハッシュテーブルで適切なスロットを見つけるためには、セットのハッシュを計算する必要があります。同等性テストを行います。
そのため、システムで実行されている他のプロセスが原因で、タイミング結果はおそらくオフになっています。壁時計時間を測定し、Pythonガベージコレクションを無効にせず、同じことを繰り返しテストしませんでした。
timeit
module を使用して、numbers
の1つの値とセットにない値を使用して、テストを実行してみてください。
import random
import sys
import timeit
numbers = [random.randrange(sys.maxsize) for _ in range(10000)]
set_ = set(numbers)
fset = frozenset(numbers)
present = random.choice(numbers)
notpresent = -1
test = 'present in s; notpresent in s'
settime = timeit.timeit(
test,
'from __main__ import set_ as s, present, notpresent')
fsettime = timeit.timeit(
test,
'from __main__ import fset as s, present, notpresent')
print('set : {:.3f} seconds'.format(settime))
print('frozenset: {:.3f} seconds'.format(fsettime))
これにより、各テストが100万回繰り返され、以下が生成されます。
set : 0.050 seconds
frozenset: 0.050 seconds
2つの異なるデータ型の理由はパフォーマンスのためではなく、機能的です。 frozensetは不変であるため、辞書のキーとして使用できます。セットはこの目的には使用できません。