Einige Lösungen zur Verbesserung der Python-Leistung.
1. Funktionsaufrufoptimierung (Speicherbereich, Zugriff auf Speicher vermeiden)
Der Kernpunkt der Programmoptimierung besteht darin, die Betriebsspanne zu minimieren. einschließlich Code Die Spanne der Ausführungszeit und die Spanne des Speicherplatzes.
1. Für große Datenmengen verwenden Sie sum
a = range(100000) %timeit -n 10 sum(a) 10 loops, best of 3: 3.15 ms per loop %%timeit ...: s = 0 ...: for i in a: ...: s += i ...: 100 loops, best of 3: 6.93 ms per loop
2. Um kleine Datenmengen zu summieren, vermeiden Sie die Verwendung von „sum“. unkompliziert Hohe kumulative Effizienz.
%timeit -n 1000 s = a + b + c + d + e + f + g + h + i + j + k # 数据量较小时直接累加更快 1000 loops, best of 3: 571 ns per loop %timeit -n 1000 s = sum([a,b,c,d,e,f,g,h,i,j,k]) # 小数据量调用 sum 函数,空间效率降低 1000 loops, best of 3: 669 ns per loop
Die Verwendung von Indizes sollte so weit wie möglich vermieden werden.
for lst in [(1, 2, 3), (4, 5, 6)]: # lst 索引需要额外开销 pass
entspricht der direkten Zuweisung eines Werts zu jedem Element.
for a, b, c in [(1, 2, 3), (4, 5, 6)]: # better pass
def force(): lst = range(4) for a1 in [1, 2]: for a2 in lst: for a3 in lst: for b1 in lst: for b2 in lst: for b3 in lst: for c1 in lst: for c2 in lst: for c3 in lst: for d1 in lst: yield (a1, a2, a3, b1, b2, b3, c1, c2, c3, d1) %%timeit -n 10 for t in force(): sum([t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7], t[8], t[9]]) 10 loops, best of 3: 465 ms per loop %%timeit -n 10 for a1, a2, a3, b1, b2, b3, c1, c2, c3, d1 in force(): sum([a1, a2, a3, b1, b2, b3, c1, c2, c3, d1]) 10 loops, best of 3: 360 ms per loop
def force(start, end): # 用于密码暴力破解程序 for i in range(start, end): now = i sublst = [] for j in range(10): sublst.append(i % 10) # 除法运算开销较大,比乘法大 i //= 10 sublst.reverse() yield(tuple(sublst), now)
def force(): # better lst = range(5) for a1 in [1]: for a2 in lst: for a3 in lst: for b1 in lst: for b2 in lst: for b3 in lst: for c1 in lst: for c2 in lst: for c3 in lst: for d1 in lst: yield (a1, a2, a3, b1, b2, b3, c1, c2, c3, d1)
r0 = [1, 2] # 可读性与灵活性 r1 = range(10) r2 = r3 = r4 = r5 = r6 = r7 = r8 = r9 = r1 force = ((a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) for a0 in r0 for a1 in r1 for a2 in r2 for a3 in r3 for a4 in r4 for a5 in r5 for a6 in r6 for a7 in r7 for a8 in r8 for a9 in r9)
Fazit: pow(x,y,z) ist besser als x**y%z .
5. Optimierung des Abteilungsbetriebsdef isprime(n): if n & 1 == 0: return False k, q = find_kq(n) a = randint(1, n - 1) if pow(a, q, n) == 1: # 比使用 a ** q % n 运算优化数倍 return True for j in range(k): if pow(a, pow(2, j) * q, n) == n - 1: # a **((2 ** j) * q) % n return True return False
Fazit: pmod ist besser als // Und % .
6. Zeitkomplexität des Optimierungsalgorithmus
In [1]: from random import getrandbits In [2]: x = getrandbits(4096) In [3]: y = getrandbits(2048) In [4]: %timeit -n 10000 q, r = pmod(x, y) 10000 loops, best of 3: 10.7 us per loop In [5]: %timeit -n 10000 q, r = x//y, x % y 10000 loops, best of 3: 21.2 us per loop
7. Sinnvoller Einsatz von Copy und Deepcopy
Für Objekte mit Datenstrukturen wie dict und list verwendet die direkte Zuweisung Referenzen. In einigen Fällen müssen Sie das gesamte Objekt kopieren. In diesem Fall können Sie copy und deepcopy im Kopierpaket verwenden. Der Unterschied zwischen diesen beiden Funktionen besteht darin, dass deepcopy rekursiv kopiert. Die Effizienz ist unterschiedlich:
Das -n nach timeit gibt die Anzahl der Durchläufe an, und die letzten beiden Zeilen entsprechen der Ausgabe von die beiden timeit, wie folgt gleich. Man erkennt, dass Letzteres um eine Größenordnung langsamer ist.
Ein Beispiel zum Kopieren:
In [23]: import copy In [24]: %timeit -n 10 copy.copy(a) 10 loops, best of 3: 606 ns per loop In [25]: %timeit -n 10 copy.deepcopy(a) 10 loops, best of 3: 1.17 us per loop
Was passiert ist, ist Folgendes: [ []] ist eine Ein-Element-Liste, die eine leere Liste enthält, daher sind alle drei Elemente von [[]] * 3 (zeigen auf) diese leere Liste. Durch Ändern eines Listenelements wird die Liste geändert. Die Modifikationseffizienz ist hoch.
8. Verwenden Sie dict oder set, um Elemente zu finden
>>> lists = [[]] * 3 >>> lists [[], [], []] >>> lists[0].append(3) >>> lists [[3], [3], [3]]
Fazit: set hat den geringsten Speicherbedarf und dict hat die kürzeste Laufzeit.
In [1]: r = range(10**7) In [2]: s = set(r) # 占用 588MB 内存 In [3]: d = dict((i, 1) for i in r) # 占用 716MB 内存 In [4]: %timeit -n 10000 (10**7) - 1 in r 10000 loops, best of 3: 291 ns per loop In [5]: %timeit -n 10000 (10**7) - 1 in s 10000 loops, best of 3: 121 ns per loop In [6]: %timeit -n 10000 (10**7) - 1 in d 10000 loops, best of 3: 111 ns per loop
Fazit: Versuchen Sie, Generatoren zum Durchqueren zu verwenden.
Die oben genannten Lösungen zur Verbesserung der Python-Leistung werden in Zukunft weitere hinzufügen. Sie können einen Blick darauf werfen, wenn Sie sie benötigen.
In [1]: %timeit -n 10 a = (i for i in range(10**7)) # 生成器通常遍历更高效 10 loops, best of 3: 933 ns per loop In [2]: %timeit -n 10 a = [i for i in range(10**7)] 10 loops, best of 3: 916 ms per loop In [1]: %timeit -n 10 for x in (i for i in range(10**7)): pass 10 loops, best of 3: 749 ms per loop In [2]: %timeit -n 10 for x in [i for i in range(10**7)]: pass 10 loops, best of 3: 1.05 s per loop