Regelinterpreter

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
tabellar
User
Beiträge: 186
Registriert: Mittwoch 4. September 2002, 15:28

Ich bin gerade an diversen Regelinterpretern dran. Habt Ihr Erfahrungen
bzgl. Geschwindigkeit und effizienter Implementierung?

Code: Alles auswählen

      elif wfnode.props['typeid']==6: #andJoin
         if wfnode.props['statusid']==1 and wfnode.props['checkid']==1:
            wfnode.updateProps('statusid',2)
            self.pool.commit();self.pool.clear()
            self.newEvent(self.userid,'wfnode','updated',wfnodeid,[])
         elif wfnode.props['statusid']==2 and wfnode.props['checkid']==1:
            wfNodesIn=self.queryMgr.getWfNodesIn(wfnodeid)
            #check: if all parent nodes are (5,1) then update(2,5) else pass
            checkid=1 #True
            for i in wfNodesIn:
             if i[2]!=5:
                checkid=0
                break
            if checkid==1:
              wfnode.updateProps('checkid',5)
              self.pool.commit();self.pool.clear()
              self.newEvent(self.userid,'wfnode','updated',wfnodeid,[])
            elif checkid==0:
               pass
         elif wfnode.props['statusid']==2 and wfnode.props['checkid']==5:
            wfnode.updateProps('statusid',5)
            wfnode.updateProps('checkid',1)            
            self.pool.commit();self.pool.clear()
            self.newEvent(self.userid,'wfnode','finished',wfnodeid,[])
Ich habe ziemlich viele if, elif, else Blöcke (ca. 10-20 Blöcke wie der
gezeigte Python-Code Block) , wo ich diverse Regeln abfrage. Ist dies
effizient? Kann man dies auch anders lösen? Diverse Regeln frage ich
über eine Datenbank ab, dies ist aber bestimmt nicht schneller ... :wink:

Tabellar
Zuletzt geändert von tabellar am Dienstag 20. Dezember 2005, 07:52, insgesamt 1-mal geändert.
tabellar
User
Beiträge: 186
Registriert: Mittwoch 4. September 2002, 15:28

Ich hätte hier mal eine Alternative zu dem if,elif,else Block oben, die
deutlich übersichtlicher [ruleCheck()] und bestimmt auch schneller ist :wink: .

Tabellar

Code: Alles auswählen

def __init__(self):
    self.compile()

def compile(self):
    s="<script>"
    e="exec"
                
    c611 ="wfnode.updateProps('statusid',2)\n"
    c611+="self.pool.commit()"
    c611+="self.pool.clear()\n"
    c611+="self.newEvent(self.userid,'wfnode','updated',wfnodeid,[])\n"
    self.cc611=compile(c611,s,e)
            
    c621 ="wfNodesIn=self.queryMgr.getWfNodesIn(wfnodeid)\n"
    c621+="checkid=1 #True\n"
    c621+="for i in wfNodesIn:\n"
    c621+=" if i[2]!=5:\n"
    c621+="    checkid=0\n"
    c621+="    break\n"
    c621+="if checkid==1:\n"
    c621+="   wfnode.updateProps('checkid',5)\n"
    c621+="   self.pool.commit()\n"
    c621+="   self.pool.clear()\n"
    c621+="   self.newEvent(self.userid,'wfnode','updated',wfnodeid,[])\n"
    c621+="elif checkid==0:\n"
    c621+="   pass"
    self.cc621=compile(c621,s,e)

    c625 ="wfnode.updateProps('statusid',5)\n"
    c625+="wfnode.updateProps('checkid',1)\n"
    c625+="self.pool.commit()\n"
    c625+="self.pool.clear()\n"
    c625+="self.newEvent(self.userid,'wfnode','finished',wfnodeid,[])"
    self.cc625=compile(c625,s,e)

def ruleCheck(self,a,b,c):
    rules={6:{1:{1:self.cc611},
              2:{1:self.cc621,
                 5:self.cc625}}}
    if rules[a][b][c]:
       exec rules[a][b][c]

                      
Zuletzt geändert von tabellar am Dienstag 20. Dezember 2005, 07:52, insgesamt 1-mal geändert.
BlackJack

Definier mal "übersichtlicher". Es ist anscheinend etwas kürzer, aber ich blicke bei den if/else Geschichten wesentlich besser durch.

Und warum sollte es schneller sein!?
tabellar
User
Beiträge: 186
Registriert: Mittwoch 4. September 2002, 15:28

BlackJack hat geschrieben:Definier mal "übersichtlicher"
Übersichtlicher deshalb, weil ich die "äusseren Hauptschleifen"
von dem eigentlichen "CheckCode" trenne und in das DICT lege,
so wird das ganze kompakter.

Code: Alles auswählen

if type==6:
   if b==1 and c==1:
      do c611
   if b==2 and c==1:
      do c621
   elif b==2 and c==5:
      do 625
   ...
elif type==7:
   if b==2 and c==1:
      do c721
   elif b==2 and c==2:
      do c722
   elif b==2 and c==5:
      do 725
   ...

ruleDict={6:{1:{1:cc611},
             2:{1:cc621,
                5:cc625}},
          7:{1:{1:cc711},
             2:{1:cc721,
                5:cc725}}}

BlackJack hat geschrieben:Und warum sollte es schneller sein!?
Ist natürlich reine Spekulation :roll: . Aber ich vermute mal, dass
die IF Abfrage im indizierten DICT schneller ist als reine "Schleifendurchgänge... vgl. LINK
Das "compile" müsste nicht sein, stört aber auch nicht grossartig.
Man müsste das ganze mal irgendwie messen...

Code: Alles auswählen

if ruleDict[6][2][1]:
   do ruleDict[6][2][1]  #==cc621

Ich hätte noch eine weitere Variante :P :

Code: Alles auswählen

import rules

class RuleChecker(Object):
  def __init__(self): 
      self.compile()

  def compile(self):
      s="<script>"
      e="exec"

      self.cc611=compile(rules.c611,s,e)
      self.cc621=compile(rules.c621,s,e)
      self.cc625=compile(rules.c625,s,e)
      #...
      
  def ruleCheck(self,a,b,c):
      rules={6:{1:{1:self.cc611},
                2:{1:self.cc621,
                   5:self.cc625}}}
      if rules[a][b][c]:
         exec rules[a][b][c]

Code: Alles auswählen

"""
    rules.py  #checkRules
"""  
#-------------------------------------------------------------------
c611="""
...
"""
#-------------------------------------------------------------------
c621="""
wfNodesIn=self.queryMgr.getWfNodesIn(wfnodeid)\n
checkid=1 #True
for i in wfNodesIn:
 if i[2]!=5:
    checkid=0
    break
if checkid==1:
   wfnode.updateProps('checkid',5)
   self.pool.commit()
   self.pool.clear()
   self.newEvent(self.userid,'wfnode','updated',wfnodeid,[])
elif checkid==0:
   pass"""
#-------------------------------------------------------------------
c625="""
wfnode.updateProps('statusid',5)
wfnode.updateProps('checkid',1)
self.pool.commit()
self.pool.clear()
self.newEvent(self.userid,'wfnode','finished',wfnodeid,[])"""
#-------------------------------------------------------------------
c721="""
...
"""
BlackJack

tabellar hat geschrieben:
BlackJack hat geschrieben:Definier mal "übersichtlicher"
Übersichtlicher deshalb, weil ich die "äusseren Hauptschleifen"
von dem eigentlichen "CheckCode" trenne und in das DICT lege,
so wird das ganze kompakter.

Code: Alles auswählen

if type==6:
   if b==1 and c==1:
      do c611
   if b==2 and c==1:
      do c621
   elif b==2 and c==5:
      do 625
   ...
elif type==7:
   if b==2 and c==1:
      do c721
   elif b==2 and c==2:
      do c722
   elif b==2 and c==5:
      do 725
   ...

ruleDict={6:{1:{1:cc611},
             2:{1:cc621,
                5:cc625}},
          7:{1:{1:cc711},
             2:{1:cc721,
                5:cc725}}}
Das ist kompakter, aber es sind auch die Informationen verlorengegangen, die in den Namen steckten, zum Beispiel das in der ersten "Ebene" ein Typ-Code steckt.
BlackJack hat geschrieben:Und warum sollte es schneller sein!?
Ist natürlich reine Spekulation :roll: . Aber ich vermute mal, dass
die IF Abfrage im indizierten DICT schneller ist als reine "Schleifendurchgänge... vgl. LINK
Da ging es um das lineare Suchen in Listen vs. Direktzugriff in ein Dictionary. Eine if-Abfrage kann auch in O(1) Zeit entschieden werden. Da würde ich keinen Geschwindigkeitsgewinn erwarten.
Das "compile" müsste nicht sein, stört aber auch nicht grossartig.
Mich würde es stören. Warum benutzt Du es? Kannst Du den Code nicht einfach als Methoden definieren und die dann in das Dictionary packen? Das gäbe Syntaxhighlighting für den Code und sicher auch bessere Fehlermeldungen die auf die richtige Stelle im Quelltext verweisen, wenn eine Ausnahme auftritt.
Man müsste das ganze mal irgendwie messen...
Hast Du vorher gemessen bzw. festgestellt das es zu langsam ist? Oder überhaupt mal geschaut wo genau die meiste Zeit verbraucht wird?

Code: Alles auswählen

if ruleDict[6][2][1]:
   do ruleDict[6][2][1]  #==cc621

Ich hätte noch eine weitere Variante :P :
<snipped>
Ich find's alles etwas unübersichtlich. Wenn die erste Entscheidung zum Beispiel immer ein Typ-Code ist, dann würde ich in eine Funktion benutzen die aufgrund des Typcodes jeweils eine entsprechende Funktion aufruft, die dann entscheidet wie's weitergeht. Und wenn die zu umfangreich werden, dann auch wieder aufteilen.
tabellar
User
Beiträge: 186
Registriert: Mittwoch 4. September 2002, 15:28

BlackJack hat geschrieben:...
Das "compile" müsste nicht sein, stört aber auch nicht grossartig.
Mich würde es stören. Warum benutzt Du es? Kannst Du den Code nicht einfach als Methoden definieren und die dann in das Dictionary packen? Das gäbe Syntaxhighlighting für den Code und sicher auch bessere Fehlermeldungen die auf die richtige Stelle im Quelltext verweisen, wenn eine Ausnahme auftritt.
Das compile habe ich aus der Not heraus genommen, weil der code, wie
ich ihn erstens in's Dict steckte, nicht funktionierte. Aber Dein Hinweis, dass eine METHODE funktioniert, habe ich gleich getestet und siehe da,
es tut!!! :P Vielen Dank. Ich werde da mal weiter probieren...

Man müsste das ganze mal irgendwie messen...
BlackJack hat geschrieben:Hast Du vorher gemessen bzw. festgestellt das es zu langsam ist? Oder überhaupt mal geschaut wo genau die meiste Zeit verbraucht wird?
Nein, gemessen habe ich nicht und Geschwindigkeitsprobleme habe ich auch nicht wirklich... Das ganze wird mal ein skalierbare Komponente,
die bewusst verlangsamt wird. Mein Hauptziel ist eine übersichtliche
Darstellung der vielen IF-Blöcke. Trotzdem hätte ich gerne einen
schnellen, übersichtlichen Regelinterpreter für den Fall der Fälle :wink:.
tabellar
User
Beiträge: 186
Registriert: Mittwoch 4. September 2002, 15:28

Ich glaub, so wird jetzt mein RuleChecker:

Code: Alles auswählen

def ruleCheck(typeid,checkid,statusid):
    checkcode=int(str(typeid)+str(checkid)+str(statusid))

       if checkcode==611:
          wfnode.updateProps('statusid',2)
          self.pool.commit();self.pool.clear()
          self.newEvent(self.userid,'wfnode','updated',wfnodeid,[])

       if checkcode==621:
          checkid=1 #True
          for i in wfNodesIn:
              if i[2]!=5:
                 checkid=0
                 break
              if checkid==1:
                 wfnode.updateProps('checkid',5)
                 self.pool.commit();self.pool.clear()
                 self.newEvent(self.userid,'wfnode','updated',wfnodeid,[])
              elif checkid==0:
                 pass
                
        if checkcode==625:
           wfnode.updateProps('statusid',5)
           wfnode.updateProps('checkid',1)           
           self.pool.commit();self.pool.clear()
           self.newEvent(self.userid,'wfnode','finished',wfnodeid,[])
Tabellar :wink:
Antworten