2017-02-07 3 views
0

Während ich an einem ziemlich großen Python (3) -Projekt gearbeitet habe, habe ich dieses merkwürdige Verhalten bei der Iteration durch ein Wörterbuch sehr selten (< 0.1% der Fälle) gemacht von Zeiten länger als normal.Warum dauert das Parsing eines Diktats sehr viel länger als gewöhnlich?

Hier ist ein sehr minimales Beispiel, die das Verhalten zeigt:

from time import perf_counter 
    from statistics import mean 

    d = {"1": 0} 
    times = [] 

    for _ in range(1000000): 
     start = perf_counter() 
     d = {k: v for k, v in d.items()} 
     diff = (perf_counter() - start) * 10e6 
     if diff > 0: 
      times.append(diff) 

    print("Mean: {}".format(mean(times))) 
    print("Max: {}".format(max(times))) 

Eg. das Ausführen dieses einmal gibt mir eine durchschnittliche Zeit von 10.806199298240244 Mikrosekunden, aber eine maximale Zeit von 31015.980057418346 Mikrosekunden, etwa 3000 mal länger als normal.

Gibt es eine Möglichkeit, ich kann dieses Verhalten vermeiden oder ist es Python inhärent?

Edit: Timed mit perf_counter() anstelle von datetime

+2

FWIW, ich kann nicht sagen, ob dieses Phänomen real ist oder nicht - jedoch ist die Verwendung von "datetime.now()" zum Timing von etwas (insbesondere etwas so kleines) wahrscheinlich sehr ungenau. "timeit.default_timer" ist wahrscheinlich ein viel besserer Ort, um dieses Phänomen zu verstehen ... – mgilson

+0

Versuchen Sie, Garbage Collection für den Test zu deaktivieren? – Ryan

Antwort

3

Die meisten der Wörterbucherstellung Aktionen, die Sie nur ein paar Nanosekunden begangen hat - und hatte als 0 Mikrosekunden behandelt worden. Als Ergebnis wird jede Aktion, die eine gewisse Verzögerung hatte, selbst wenn die Verzögerung einige Mikrosekunden betrug, als eine große Änderung betrachtet - und jedes 0 Ergebnis senkt den Durchschnitt außerhalb seiner Grenzen.

Auch die maximalen Ergebnisse sind stark deutlich vom Rest (sie sind in der Regel wegen CPU-Zeug) - mit Abweichung kann den Unterschied deutlich zeigen, und markieren Sie den allgemeinen Bereich der normalen Ergebnisse.


from time import perf_counter 
from statistics import mean, stdev 

d = {"1": 0} 
times = [] 

for _ in range(100000): 
    start = perf_counter() 
    d = {k: v for k, v in d.items()} 
    diff = (perf_counter() - start) * 10e6 
    if diff > 0: 
     times.append(diff) 

print("Mean: {}".format(mean(times))) 
print("Stddev: {}".format(stdev(times))) 
print("Max: {}".format(max(times))) 

Versuchen Sie, und Sie sollten weniger extreme Unterschiede - und viel kleinere Ergebnisse als time.time oder datetime.now verwenden (auch bei der Standardabweichung einen Blick):

Mean: 11.520527719010078 
Stddev: 4.476865528640042 
Max: 443.1869339160954 
+0

'time.perf_counter' oder' timeeit.default_timer' sollte wahrscheinlich anstelle von 'time.time' verwendet werden. Außerdem ist es wahrscheinlich eine gute Idee, "Zeit" zu verwenden, um die ganze Sache zu erledigen, da sie häufig vergessene Details wie das Ausschalten des Müllsammlers behandelt (was möglicherweise der Schuldige für die wenigen langen Zyklen hier ist). Unglücklicherweise ist mir keine Möglichkeit bekannt, Ihnen ein Histogramm der tatsächlichen Ergebnisse zu geben ... – mgilson

+0

@mgilson Ich glaube, dass matplotlib – Uriel

+0

@mgilson zu 'perf_counter' geändert werden konnte - die Ergebnisse sind genauer und viel kleiner. Vielen Dank! – Uriel

Verwandte Themen