Optimierung

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Boa
User
Beiträge: 190
Registriert: Sonntag 25. Januar 2009, 12:34

Hallo,

Ich habe ein kleines Programm geschrieben, welches in einem Modell für verteilten Speicher Verfügbarkeiten vorberechnen soll, damit dort wo es dann genutzt wird eine einfach Datenbankabfrage ausreicht. Dazu habe ich den line-profiler installiert, mir fällt aber gerade keine besonders tolle Möglichkeit zur Verbesserung ein. Habt ihr Tipps für die Optimierung? Meint ihr ich soll das ganze lieber in C schreiben?
Damit der Code zumindest etwas Sinn macht; Die Variable C zählt einfach die Verfügbarkeiten hoch. In dem Beispiel fange ich an mit 15 Speichern, die alle die Verfügbarkeit 0,5 haben. Statt mit Gleitkommazahlen zu rechnen nehme ich die Verfügbarkeit Mal 100, damit ich mit ganzzahligen Werten rechnen kann. Dann wird die Wahrscheinlichkeit berechnet, dass mindestens k Speicher auf einmal verfügbar sind.
Was natürlich noch möglich wäre ist das Programm mehrfach mit unterschiedlichen Werten zu starten, um das ganze "Mehrprozess fähig" zu machen und die Ergebnisse am Ende zusammenzufügen. Außerdem werden zur Zeit manche Wahrscheinlichkeiten noch zweimal berechnet (P([0,5;0,6;0,4])=P(0,6;0,4;0,5), die Wahrscheinlichkeiten sind gleich, da nur die Position der Wahrscheinlichkeiten vertauscht wurde).

Hier die Ausgabe:

Code: Alles auswählen

kernprof.py -lv availability.py
[...]
File: availability.py
Function: main at line 8
Total time: 43.5855 s

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
     8                                           @profile    
     9                                           def main():        
    10         1            0      0.0      0.0      availabilities_dict = {}
    11         1            0      0.0      0.0      C = 505050505050505050505050505050
    12       100            0      0.0      0.0      for k in range(1,100):
    13        99            0      0.0      0.0          availabilities_dict[k] = {}
    14         3            0      0.0      0.0      while True:
    15         3            0      0.0      0.0          C += 5
    16         3            0      0.0      0.0          node_availabilities = C
    17         3            0      0.0      0.0          availabilities_list = []
    18        45         1000     22.2      0.0          while True:
    19        45            0      0.0      0.0              availabilities_list.append(node_availabilities % 100)
    20        45            0      0.0      0.0              node_availabilities /= 100
    21        45            0      0.0      0.0              if node_availabilities == 0: 
    22         3            0      0.0      0.0                  break
    23        33            0      0.0      0.0          for k in range(1,len(availabilities_list)+1): # number of storage targets sufficient for object availability
    24        31         1000     32.3      0.0              print "k:"+str(k)
    25        31            0      0.0      0.0              result = 0 # availability
    26    505376      1723110      3.4      4.0              for S in powerset(availabilities_list, k):
    27    505346       639040      1.3      1.5                  av = uv = 1
    28   4516747      5866318      1.3     13.5                  for a in S:
    29   4011401      5777364      1.4     13.3                      av *= a
    30    505346       955055      1.9      2.2                  unavailabilities_list = list(availabilities_list)
    31   4516747      5864336      1.3     13.5                  for e in S:
    32   4011401      6135366      1.5     14.1                      unavailabilities_list.remove(e)
    33   7642909     10566572      1.4     24.2                  for u in [100-u_b for u_b in unavailabilities_list]:
    34   3568781      5230303      1.5     12.0                      uv *= u
    35    505345       825050      1.6      1.9                  result += av * uv
    36        30         1000     33.3      0.0              availabilities_dict[k][C] = 1.0*result/(pow(100,len(availabilities_list)))
Und das ganze Programm availability.py:

Code: Alles auswählen

from itertools import *
from sys import exit
def powerset(some_list, minimal_number_of_elements):
    '''Powerset of some_list, where some_list is a multiset'''
    for subset in chain.from_iterable(combinations(some_list, r) for r in range(minimal_number_of_elements,len(some_list)+1)):
        yield list(subset)

@profile    
def main():        
    availabilities_dict = {}
    C = 505050505050505050505050505050
    for k in range(1,100):
        availabilities_dict[k] = {}
    while True:
        C += 5
        node_availabilities = C
        availabilities_list = []
        while True:
            availabilities_list.append(node_availabilities % 100)
            node_availabilities /= 100
            if node_availabilities == 0: 
                break
        for k in range(1,len(availabilities_list)+1): # number of storage targets sufficient for object availability
            print "k:"+str(k)
            result = 0 # availability
            for S in powerset(availabilities_list, k):
                av = uv = 1
                for a in S:
                    av *= a
                unavailabilities_list = list(availabilities_list)
                for e in S:
                    unavailabilities_list.remove(e)
                for u in [100-u_b for u_b in unavailabilities_list]:
                    uv *= u
                result += av * uv
            availabilities_dict[k][C] = 1.0*result/(pow(100,len(availabilities_list)))
            

if __name__ == "__main__":
    main()
    
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo,

einfach mal mit PyPy starten, dann erledigen sich viele Sachen schon. Ansonsten kann man die Berechnung der avs und uvs noch mit filter zusammenfassen und das Erzeugen von ``[100-u_b for u_b in unavailabilities_list]`` ist überflüssig.
Das Leben ist wie ein Tennisball.
BlackJack

Bei dem was mit `unavailabilities_list` und `S` gemacht wird fallen einem auch ziemlich direkt Mengenoperationen ein. Ein `remove()` auf eine Liste ist vergleichsweise teuer.

Edit: Bin ich gerade blind? Wo wird die äussere ``while True``-Schleife eigentlich abgebrochen?
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

BlackJack hat geschrieben:Edit: Bin ich gerade blind? Wo wird die äussere ``while True``-Schleife eigentlich abgebrochen?
So wie ich es sehe: gar nicht.

Mit PyPy würde die Endlosschleife aber bestimmt höchstens 20% der Zeit brauchen.
Boa
User
Beiträge: 190
Registriert: Sonntag 25. Januar 2009, 12:34

Hi,

Danke für den Tipp mit pypy. Leider kann ich noch nicht sagen ob es damit viel schneller geht, weil der line-profiler nicht damit funktioniert. Das mit dem Erzeugen der unnötigen liste habe ich auch weggelassen.
Mengenoperationen kann ich leider nicht verwenden, da ich auf Multisets arbeite, also durchaus ein Element mehrfach vorkommt.
Die Schleife breche ich zur Zeit noch über KeyboardInterrupt ab. Ich denke ich baue dann noch eine Pause und Abbruch Funktion ein.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Boa hat geschrieben:Mengenoperationen kann ich leider nicht verwenden, da ich auf Multisets arbeite, also durchaus ein Element mehrfach vorkommt.
Du könntest aus der Liste einfach ein Dictionary machen, als Wert verwendest du dann die Anzahl der Vorkommen. Statt O(n) landest du dann bei O(1).
Das Leben ist wie ein Tennisball.
Antworten