functools.total_ordering を使う場合は、クラスは __eq__() と __lt__() のみ実装し、total_ordering で修飾されています。使わない場合は、クラスは残りの __ne__()、__le__()、__gt__()、__ge__()も実装されています。
==、!=、<、<=、>、>= の6演算子全てを呼んだの速度と、== と < だけを呼んだ場合の速度の、二通りについて比較を行います。
6演算子全てを呼ぶベンチマークのソースコードです。
rom functools import total_ordering
from benchmarker import Benchmarker
with Benchmarker(1000000, width=20, cycle=3, extra=1) as bench:
@bench("total_ordering")
def _(bm):
# クラス定義
@total_ordering # デコレータ
class Stored(object): # __lt__() と __eq__() のみ定義
def __init__(self, value):
self.value = value
def __lt__(self, rhs):
return self.value < rhs.value
def __eq__(self, rhs):
return self.value == rhs.value
lhs = Stored(1)
rhs = Stored(2)
for _ in bm:
# 6演算子全てを呼び出し
lhs == rhs
lhs != rhs
lhs < rhs
lhs <= rhs
lhs > rhs
lhs >= rhs
@bench("normal")
def _(bm):
# クラス定義
class Stored(object): # 6演算子全てを定義
def __init__(self, value):
self.value = value
def __lt__(self, rhs):
return self.value < rhs.value
def __le__(self, rhs):
return self.value <= rhs.value
def __gt__(self, rhs):
return self.value > rhs.value
def __ge__(self, rhs):
return self.value >= rhs.value
def __eq__(self, rhs):
return self.value == rhs.value
def __ne__(self, rhs):
return self.value != rhs.value
lhs = Stored(1)
rhs = Stored(2)
for _ in bm:
# 6演算子全てを呼び出し
lhs == rhs
lhs != rhs
lhs < rhs
lhs <= rhs
lhs > rhs
lhs >= rhs
測定結果です。
## benchmarker: release 4.0.1 (for python) ## python version: 3.7.3 ## python compiler: Clang 6.0 (clang-600.0.57) ## python platform: Darwin-18.7.0-x86_64-i386-64bit ... ## Ranking real normal 1.1379 (100.0) ******************** total_ordering 1.7093 ( 66.6) *************total_ordering は使わず、6つの演算子を自力で定義した方が、動作速度は速いです。
公式ドキュメントに書いてある通りの結果となりました。
続いて、total_ordering を使っているクラスでも定義されている、== と < だけを呼び出した場合の動作速度を比較します。
rom functools import total_ordering
from benchmarker import Benchmarker
with Benchmarker(1000000, width=20, cycle=3, extra=1) as bench:
@bench("total_ordering")
def _(bm):
# クラス定義
@total_ordering # デコレータ
class Stored(object): # __lt__() と __eq__() のみ定義
def __init__(self, value):
self.value = value
def __lt__(self, rhs):
return self.value < rhs.value
def __eq__(self, rhs):
return self.value == rhs.value
lhs = Stored(1)
rhs = Stored(2)
for _ in bm:
# == と < だけ呼び出し
lhs == rhs
lhs < rhs
@bench("normal")
def _(bm):
# クラス定義
class Stored(object): # 6演算子全てを定義
def __init__(self, value):
self.value = value
def __lt__(self, rhs):
return self.value < rhs.value
def __le__(self, rhs):
return self.value <= rhs.value
def __gt__(self, rhs):
return self.value > rhs.value
def __ge__(self, rhs):
return self.value >= rhs.value
def __eq__(self, rhs):
return self.value == rhs.value
def __ne__(self, rhs):
return self.value != rhs.value
lhs = Stored(1)
rhs = Stored(2)
for _ in bm:
# == と < だけ呼び出し
lhs == rhs
lhs < rhs
測定結果です。
## benchmarker: release 4.0.1 (for python) ## python version: 3.7.3 ## python compiler: Clang 6.0 (clang-600.0.57) ## python platform: Darwin-18.7.0-x86_64-i386-64bit ... ## Matrix real [01] [02] [01] total_ordering 0.4125 100.0 100.3 [02] normal 0.4136 99.7 100.0結果、動作速度は同じでした。
total_ordering が動作速度的に不利になるのは、未定義の演算子の結果を他の演算子から推測する処理部分にあるようです。

0 件のコメント:
コメントを投稿