Au sens de Java et C ++, il semble que les références de membres de classe soient rapides et les références de mappe lentes, mais ce n'est pas toujours le cas avec Python. C'est parce que Python traite la classe comme une sorte de dict en interne, donc même si vous utilisez simplement dict dans un usage normal, ce ne sera pas si désavantageux en termes de vitesse [^ 1].
[^ 1]: Il a été souligné qu'il était nécessaire de mesurer séparément l'allocation de mémoire et le temps de référence, de sorte que certains éléments de mesure ont été corrigés. Une partie du contenu a été modifiée en conséquence.
Script de validation
import collections
import random
import time
#
#Implémenté en classe.
#
class EClass:
def __init__(self, x, y):
self.x = x
self.y = y
def test_class(n):
l = []
t1 = time.time()
for _ in range(n):
x = random.random()
y = random.random()
e = EClass(x, y)
l.append(e)
t2 = time.time()
for e in l:
x = e.x
y = e.y
z = x + y
t3 = time.time()
return (t1, t2, t3)
#
#Implémenté en classe (avec slots).
#
class EClassSlot:
__slots__ = ["x", "y"]
def __init__(self, x, y):
self.x = x
self.y = y
def test_class_slot(n):
l = []
t1 = time.time()
for _ in range(n):
x = random.random()
y = random.random()
e = EClassSlot(x, y)
l.append(e)
t2 = time.time()
for e in l:
x = e.x
y = e.y
z = x + y
t3 = time.time()
return (t1, t2, t3)
#
#Mis en œuvre avec dict.
#
def test_dict(n):
l = []
t1 = time.time()
for _ in range(n):
x = random.random()
y = random.random()
e = {"x": x, "y": y}
l.append(e)
t2 = time.time()
for e in l:
x = e["x"]
y = e["y"]
z = x + y
t3 = time.time()
return (t1, t2, t3)
#
#Mis en œuvre avec liste.
#
def test_list(n):
l = []
t1 = time.time()
for _ in range(n):
x = random.random()
y = random.random()
e = [x, y]
l.append(e)
t2 = time.time()
for e in l:
x = e[0]
y = e[1]
z = x + y
t3 = time.time()
return (t1, t2, t3)
#
#Implémenté avec tuple.
#
def test_tuple(n):
l = []
t1 = time.time()
for _ in range(n):
x = random.random()
y = random.random()
e = ((x, y, None))
l.append(e)
t2 = time.time()
for i, e in enumerate(l):
x = e[0]
y = e[1]
z = x + y
t3 = time.time()
return (t1, t2, t3)
#
#Implémenté avec namedtuple.
#
ENamedTuple = collections.namedtuple("E", ("x", "y"))
def test_namedtuple(n):
l = []
t1 = time.time()
for _ in range(n):
x = random.random()
y = random.random()
e = ENamedTuple(x, y)
l.append(e)
t2 = time.time()
for i, e in enumerate(l):
x = e.x
y = e.y
z = x + y
t3 = time.time()
return (t1, t2, t3)
#
#Faites un test.
#
tests = [
("class\t", test_class),
("class_slot", test_class_slot),
("dict\t", test_dict),
("list\t", test_list),
("tuple\t", test_tuple),
("namedtuple", test_namedtuple)
]
n = 5000000
print("test\t\talloc\trefer\ttotal")
for test, function in tests:
t1, t2, t3 = function(n)
print("%s\t%0.2f\t%0.2f\t%0.2f"
%(test, t2 - t1, t3 - t2, t3 - t1))
Les résultats sont présentés ci-dessous, et en se concentrant sur le temps requis pour l'opération de référence, on peut voir que l'implémentation utilisant dict n'est pas très différente de l'implémentation utilisant la classe normale. Si vous utilisez slot, vous pouvez y accéder un peu plus rapidement que dict, mais la création d'un objet prend presque deux fois plus de temps que dict et list, donc si vous envisagez d'inclure le temps nécessaire pour sécuriser les éléments, cette différence est à ce sujet. Cela devient un nombre presque dénué de sens.
Résultat d'exécution
test alloc refer total
class 7.68 0.84 8.52
class_slot 6.41 0.76 7.17
dict 3.64 0.79 4.43
list 4.00 0.72 4.72
tuple 2.41 0.96 3.37
namedtuple 7.50 1.70 9.20
Bien que la liste soit la plus rapide pour les opérations de référence, il n'y a aucune raison de l'utiliser aux fins ci-dessus, compte tenu du temps et des efforts nécessaires pour spécifier un élément comme index. En fait, il s'est avéré que le tuple auquel je m'attendais secrètement n'était pas si rapide en termes de vitesse de référence. Cependant, c'est le plus rapide pour sécuriser les éléments, et étant donné que les valeurs ne peuvent pas être modifiées après la création, on peut dire que cela suffit pour échanger de petites valeurs.
namedtuple est très lent à générer et à référencer. En effet, namedtuple recherche les membres dans l'ordre depuis le début à chaque fois, et bien que l'efficacité de la mémoire soit bonne, la vitesse devient plus lente à mesure que le nombre d'éléments augmente.
Recommended Posts