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 

 )