Sirius3 hat geschrieben:@Serpens66: Du mußt eben alles, was Du Dir wünschst, Stück für Stück implementieren und hier besonders wichtig, jeden Teil gründlich testen. Was hast Du denn schon versucht?
Ist ja schon alles implementiert.
Was ich nun suche ist eine Alternative, wie das ganze eben "parallel sicher" ist, also 5 mal gleichzeitig ratelimit mit derselben Website aufgerufen wird, während nur noch 3 mal aktuell erlaubt wäre, sodass es korrekt umgesetzt wird.
Meine Funktion sieht so aus (wie gesagt ich hoffe es geht deutlich übersichtlicher und besser geschrieben):
Code: Alles auswählen
def limitkontrolle(self,website,Zeitlimit,CallLimit,Limitcount):
anfangszeit = int(time.time() * 1000)
#Zeitlimit hier die Zeit in milisek eintragen, wie weit die CallLimit calls auseinander sein duerfen
#CallLimit Anzahl der Calls in in der Zeit Zeitlimit gemacht werden duerfen
Ergebnisda = False
timer = 0
while not self.Datadict[website]["Limitdict"].get(Limitcount-1): # solange es den eintrag zuvor noch nicht gibt, nicht weitermachen
if Limitcount==0: # wenn limitcount 0, dann ausnahme machen
break
timer += 1
sleep(0.001)
if timer>=10000: # notausstieg falls fehler in schleife und sonst unendlich (max 10 sek)
print("unendlich LOOP schleife {} 1. Laenge:{}. Limitcount:{}".format(website,len(self.Datadict[website]["Limitdict"]),Limitcount))
self.Datadict[website]["Schleifenposition"] = 0
self.Datadict[website]["Limitdict"] = {}
self.Datadict[website]["Limitcounter"] = 1
#break
return False
continue # unendliche oft im kreis drehen, bis eintrag exisitert
while not Ergebnisda:
sleepen = 0
zeit = int(time.time() * 1000)
if len(self.Datadict[website]["Limitdict"]): # wenn schon Eintraege enthalten sind
for position in range(self.Datadict[website]["Schleifenposition"],len(self.Datadict[website]["Limitdict"])+min(self.Datadict[website]["Limitdict"])): # min addieren heisst zu anfang null addieren. Aber wenn z.b alle eintraege von 0 bis 4 geloescht wurden, startet es bei 5, dann muss das hier auch bei 5 starten und bis laenge+5 gehen
differenz = zeit - self.Datadict[website]["Limitdict"][position] # jetzige Zeit mit erstem Eintrag vergleichen
if differenz <= Zeitlimit: # hier die Zeit in milisek eintragen, wie weit die x calls auseinander sein duerfen
if Limitcount - position >= CallLimit: # wenn die laenge der liste nun CallLimit oder mehr uebersteigt, dann sleepen
sleepen = self.Datadict[website]["Limitdict"][position] + Zeitlimit - zeit
self.Datadict[website]["Schleifenposition"] = position
break
else: # falls nicht,dann einfach weiter
self.Datadict[website]["Schleifenposition"] = position # gibt an, bis zu welchem Punkt hinterher geloescht werden soll
break # und for schleife beenden, da alles fertig
else: # andernfalls alle listenelemte durchgehen, diese evlt rausschmeissen und wenn ueberall differenz <= y, dann liste loeschen und zeit als erten eintrag setzen
if position == len(self.Datadict[website]["Limitdict"])+min(self.Datadict[website]["Limitdict"])-1: # wenn das letzte listenelement erreicht ist und differenz offensichtlich immernoch groesser y, dann liste loeschen und nur noch neue zeit drin lassen
self.Datadict[website]["Schleifenposition"] = position # gibt an, bis zu welchem Punkt hinterher geloescht werden soll
break
else:
continue # naechste position durchgehen
if sleepen:
sleep(sleepen/1000) # sleepen in sekunden
continue # von vorne, damit zeit neu genommen wird
if not sleepen:
self.Datadict[website]["Limitdict"][Limitcount]=int(time.time() * 1000)
Ergebnisda = True
break
endzeit = int(time.time() * 1000)
dauer = (float(endzeit)-float(anfangszeit))/1000 # in sek
if dauer>=0.5:
self.history("Ein Apicall fuer {} wurde aufgrund des API Limits {} sekunden zurueckgehalten. Evlt. pruefen, ob limit optimaler genutzt werden kann, da durch das Warten viel Zeit verloren geht.".format(website,dauer),0,0,1)
return True # Call kann gemacht werden
self.Datadict[website]["Limitdict"] ist ein dictionary, welches allerdings Zahlen als key verwendet.
Dies habe ich als nötig erachtet, damit ich die Reihenfolge überwachen kann.
self.Datadict[website]["Limitcounter"] ist eine Zahl, nämlich der aktuell neuste Key des Limitdicts.
self.Datadict[website]["Schleifenposition"] ist ebenfalls eine Zahl, ich weiß die Verwendung garnicht mehr so genau... aber anhand meiner Kommentare aus dem Code entnehme ich mal, dass es verwendet wird um das Limitdict außerhalb der limitkontrolle ab und zu auszumisten, sodass es nicht unendlich lang wird, sondern nur die relevanten Einträge enthält.
Es funktioniert nun so:
Es werden mithilfe von Threads 5 Funktionen aufgerufen, um 5 api calls gleichzeitig bei derselben Website zu machen. Diese 5 Funktionen bekommen den aktuellen Limitcounter + 1 bis + 5 übergeben. Die Funktionen rufen, bevor sie den API Call machen, die limitkontrolle auf.
Zuerst wird überprüft, ob es im Limitdict bereits den vorangegangenen Eintrag gibt. Dies soll sicherstellen, dass Limitcount+1 zuerst ausgeführt wird und danach die anderen. Sicherheitshalber ist dort ein notausstieg eingebaut.
Danach wird einfach überprüft, wieviele Calls in dem erlaubten Zeitlimit gemacht wurden, und ob noch Platz für weitere ist. Wenn nicht, dann wird entprechend sleep durchgeführt. Sobald dann wieder möglich wird ein neuer Eintrag in das Limitdict aufgenommen mit dem aktuellen timestamp.
Am liebsten würde ich nun den ganzen komplizierten Limitcount(er), Schleifenposition und den "unendlich Loop" Kram weglassen. Das Limitdict könnte man auch als Liste führen.
Das alles wegzulassen funktioniert, wenn ich die Aufrufe in Reihe, also nacheinander mache. Aber bei mehreren gleichzeitig funktioniert das halt nicht.
Daher ist die Frage nun, wie ich den Aufbau dennoch vereinfachen kann.
edit:
@__deets__:
Ich schick diesen Post jetzt erstmal ab, ohne deine Antwort zu lesen, schaue es mir aber sofort an (bzw vllt besser morgen, ist schon spät, danke
)