Durchlaufzeit von Funktionen rausfinden / Datum angeben

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.
Serpens66
User
Beiträge: 259
Registriert: Montag 15. Dezember 2014, 00:31

Ich möchte rausfinden, wie lange meine Funktionen für einen Durchlauf brauchen. Der grobe Aufbau des Skripts ist ungefähr so:

Code: Alles auswählen

def kontrolle():
	if x:
		return(1)
	if not(x):
		return(0)

def reaktion():
	if x:
		kontrolle()
	if not (x):
		return()

def suchen():
	while (True):
		if x:
			reaktion()
		if not(x):
			sleep(15)

suchen()
Ich möchte nun sehen wie lange ein while Durchlauf dauert. Sowohl wenn nur suchen() ausgeführt wird, als auch wenn noch auf die anderen definitionen zugegriffen werden wird. Demnach brauche ich eine Art timer, den ich starten, stoppen und auch wieder resetten kann. Habe gerade time.clock probiert, aber den kann ich glaube ich nicht stoppen oder resetten. In der Dokumentation wird noch auf perf_counter() und process_time() hingewiesen. Aber auch diese scheinen kein start, stop und resett zu unterstützen, oder? Der Unterschied zwischen den beiden letzteren ist, wenn ich das richtig verstanden habe, dass bei einem "sleep" nicht mit eingerechnet wird, richtig?
Kann ich diese für mein Vorhaben doch gebrauchen, oder gibt es noch andere Möglichkeiten?



Ich möchte eine Logdatei erstellen. Wie das geht, kann ich ja der Logging Dokumentation entnehmen. Nun möchte ich, dass darin auch Datum und Uhrzeit dabei steht. Es muss nicht bei jedem einzelnen Ereignis sein, am besten wäre es, wenn ich selbst in mein Skript schreiben könnte, an welcher stelle im Log eine Uhrzeit dazu angegeben werden soll.
edit: habe zum logging gerade vermutlich gefunden was ich suche, mal schauen ob das klappt: https://docs.python.org/3/howto/logging ... n-messages
Boa
User
Beiträge: 190
Registriert: Sonntag 25. Januar 2009, 12:34

Eine andere Möglichkeit die Zeit für kleine Funktionen zu stoppen bietet das timeit Modul:
http://ideone.com/GcPoV1

Code: Alles auswählen

number
gibt dabei die Anzahl der Durchläufe an.
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

@Serpens66: ich weiß jetzt nicht, was der Code zum Verständnis der Frage beitragen soll. Da ist jedenfalls so einiges schlecht dran: Einrücktiefe sollten 4 Leerzeichen sein. Du übergibst das x nicht als Parameter, das fällt einfach so vom Himmel. Weder return noch not sind Funktionen, die Klammern sind also fehl am Platz. Was denkst Du, hat «return()» als Rückgabewert? Die Rückgabewerte werden auch nirgends verwendet. Wenn es ein «if» und ein «if not» gibt, dann ist das zweite «if» eigentlich ein «else». Auch while ist keine Funktion. Wenn Du die Zeit wissen willst, die eine Funktion braucht, gibt es sogenannte Profiler. Bei Python wird schon einer mitgeliefert, den man über

Code: Alles auswählen

python -m cProfile programm.py
aufrufen kann.
Serpens66
User
Beiträge: 259
Registriert: Montag 15. Dezember 2014, 00:31

@Boa: danke schaue ich mir mal an :)

@Sirius:
Das ist natürlich nicht mein Code :D wie ich geschrieben habe, ging es nur darum meinen Aufbau zu zeigen. Ich wollte damit zeigen, dass ich eine while schleife habe, welche unter gewissen umständen noch andere Funktionen aufruft und wie das also miteinander verkettet ist. Dies wollte ich zeigen, damit sichtbar wird, dass es nicht hilft time.clock zu verwenden, weil durch die while schliefe die Zeit immer weiter läuft und nicht wieder resettet wird.
Ach und ich habe diesen Beispielcode hier im "antwort erstellen" geschrieben, weshalb das TAB mehr Leerzeichen als üblich hat.


Danke für das Stichwort Profiler :)
Also nutze ich den dann so, wie hier beschrieben auch in Python3, richtig? https://docs.python.org/2/library/profi ... e-cProfile
Auf den ersten Blick sehe ich keinen Befehl für resett... hmm mal genauer lesen...
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Serpens66 hat geschrieben:Ach und ich habe diesen Beispielcode hier im "antwort erstellen" geschrieben, weshalb das TAB mehr Leerzeichen als üblich hat.
Du hast den Hinweis falsch verstanden. Verwende bei Python-Programmen für die Einrückung *immer* Leerzeichen. Bei den meisten Editoren ist es außerdem einstellbar, dass Tabs sofort durch eine beliebige Anzahl an Leerzeichen ersetzt werden.
Serpens66 hat geschrieben:Also nutze ich den dann so, wie hier beschrieben auch in Python3, richtig? https://docs.python.org/2/library/profi ... e-cProfile
Ausprobieren ;-)
Das Leben ist wie ein Tennisball.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Die Dokumentation gibt es auch fuer Python3: https://docs.python.org/3.3/library/profile.html
Serpens66
User
Beiträge: 259
Registriert: Montag 15. Dezember 2014, 00:31

@EyDu: ich meine mich zu erinnern, dass BlackJack (oder vllt auch jemand anders in meinen ersten Threads) mir geraten hatte im Notepad++ den TAB auf 4 Leerzeichen umzustellen UND alle Leerzeichen durch TABs zu ersetzen, damit ich nicht das Problem habe, dass etwas nicht funktioniert, weil ich iwo ausversehen 5 Leerzeichen gesetzt habe.
Also wäre die sinnvolle Vorgehensweise doch tatsächlich nur TABs und keine Leerzeichen zum einrücken zu verwenden? Du siehst die Argumentation für nur TAB, was ist deine Arguemtation für nur Leerzeichen?

@cofi: danke für den Link, google hatte das iwie nicht gefunden ("python 3 profiler")


so jetzt dann mal gucken, ob ich das auch mit start/stop/resett verwenden kann :)
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Serpens66 hat geschrieben:@EyDu: ich meine mich zu erinnern, dass BlackJack (oder vllt auch jemand anders in meinen ersten Threads) mir geraten hatte im Notepad++ den TAB auf 4 Leerzeichen umzustellen UND alle Leerzeichen durch TABs zu ersetzen, damit ich nicht das Problem habe, dass etwas nicht funktioniert, weil ich iwo ausversehen 5 Leerzeichen gesetzt habe.
Das hat BlackJack dir sicher nicht geraten. Er hat wahrscheinlich das selbe geschrieben wie ich: Zum Einrücken nur Leerzeichen, Einrückungstiefe sind vier Leerzeichen und das sich Editoren so umstellen lassen, dass statt Tabs Leerzeichen eingefügt werden.
Serpens66 hat geschrieben:Also wäre die sinnvolle Vorgehensweise doch tatsächlich nur TABs und keine Leerzeichen zum einrücken zu verwenden? Du siehst die Argumentation für nur TAB, was ist deine Arguemtation für nur Leerzeichen?
Prinzipiell ist es egal, ob man nur Tabs oder nur Spaces zur Einrückung verwendet. Hauptsache ist, dass diese nicht vermischt werden. Das kann nicht nur extrem unleserlich werden, sondern auch zu Syntaxfehlern führen. Python interpretiert Tabs als 8 Leerzeichen, die meisten Editoren stellen Tabs aber als 4 Leerzeichen dar. Um allen Problem aus dem Weg zu gehen, wird für Pythonen empfohlen, nur Leerzeichen zu verwenden. Lies dir mal PEP 8 durch.
Das Leben ist wie ein Tennisball.
Serpens66
User
Beiträge: 259
Registriert: Montag 15. Dezember 2014, 00:31

@EyDu:
habe gerade den Post gesucht und du hast recht, ich hab das wohl genau verkehrt herum verstanden, obwohl ich tatsächlich tabs in leerzeichen habe wandeln lassen :D
http://www.python-forum.de/viewtopic.php?f=2&t=35300 (hier der Post von Sirius3 in dem er von Tab redet... ich sehe leider keine Möglichkeit direkt auf den Post von Sirius3 zu verlinken, wie geht das in diesem Forum?)
also danke dass du mich nochmal darauf hingewiesen hast, ich hab es nämlich vergessen und sie sogar vermischt genutzt (wobei Python sie ja glücklicherweise in Leerzeichen umwandelt, so gesehen habe ich keine Tabs benutzt, aber gedacht ich hätte es, das war mein Gedankenfehler :D)


Um das Thema nochmal etwas weiterzuführen:
Mein aktuelles Skript braucht noch zu lange. Wobei vermutlich API Abfragen für die größten Verzögerungen sorgen, da Berechnungen (also mathematik) in Python ja nicht lange dauern sollte, richtig? Nun wird es ja allgemein geraten und ist auch Konvetion, die verschiedenen Aufgaben zu verteilen. Das heißt mein Skript welches Berechnungen anstellt, sollte getrennt von dem Skript sein, welches die API Abfrage macht usw.

Das stellt sich mir jetzt die Frage, wieviel Python gleichzeitig machen kann. Angenommen mein Skript sieht so aus (bitte nicht auf namensgebung oderso eingehen, ich denke es mir nur eben schnell aus und es dient nur zur anschauung)
eckige klammern sind nur anmerkungen zum srkipt, was da noch alles stehen könnte

Code: Alles auswählen

def rechnung():
    a=ersteapi()
    b=zweiteapi()
    c=dritteapi()
    d=a+b+c
    [... noch viele rechnungen]
    e=api4()
    f=api5()
    [...viele rechnungen]
    meinergebnis = [gesamtergebnis der Rechnungen]
    print(meinergebnis)
Gehen wir mal davon aus, dass jede dieser API funktionen nun irgendwas irgendwo abfragt und um das ergebnis zurückzuliefern braucht jede fkt 2 sekunden. Würde Python nun die ersten drei API's zeitgleich abfragen, oder würde es erst auf das ergebnis der ersten API warten, bis er überhaupt anfängt, die "zweiteapi()" abzufragen?
Ich vermute er geht alles der Reihe nach und wartet auf das Ergebnis oder? Wenn ja, wie kann man es schaffen, dass Aufgaben zeitgleich erledigt werden um Zeit zu sparen? Oder läuft es doch ganz anders als icih es denke?
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Parallelisieren kannst du die Abfragen mittels Threads. Schaue dazu mal in die Dokumentation des threading-Moduls. Im Prinzip brauchst du nicht mehr als die start- und die join-Methode auf Threads.
Das Leben ist wie ein Tennisball.
Serpens66
User
Beiträge: 259
Registriert: Montag 15. Dezember 2014, 00:31

EyDu hat geschrieben:Parallelisieren kannst du die Abfragen mittels Threads. Schaue dazu mal in die Dokumentation des threading-Moduls. Im Prinzip brauchst du nicht mehr als die start- und die join-Methode auf Threads.
okay, vielen Dank, schaue ich mir dann bei Gelegenheit an :) (soviele offene Baustellen zurzeit :D)
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Ungetestet:

Code: Alles auswählen

import threading
import time
import random


class Foo(threading.Thread):
    def __init__(self, name):
        threading.Thread.__init__(self)
        
        self.name = name
        self.result = None
    
    
    def run(self):
        print "Calculating {}".format(self.name)
        time.sleep(random.random() * 10)
        result = random.randint(1, 42)
        print "{} = {}".format(self.name, result)
        self.result = result


if __name__ == "__main__":
    threads = map(Foo, ("spam", "ham", "eggs"))
    for thread in threads:
        thread.start()
    
    for thread in threads:
        thread.join()
    
    print "sum =", sum(thread.result for thread in threads)
Das Leben ist wie ein Tennisball.
Serpens66
User
Beiträge: 259
Registriert: Montag 15. Dezember 2014, 00:31

vielen Dank für das beispiel.
Ich habe die run fkt noch etwas abgewandelt, damit ich mir die funktionsweise besser veranschaulichen kann:

Code: Alles auswählen

    def run(self):
        print ("Calculating {}".format(self.name))
        randomnumber = random.randint(1, 5)
        print("radomnumber für {} ist {}".format(self.name, randomnumber))
        time.sleep(randomnumber)
        result = random.randint(1, 42)
        print ("{} = {}".format(self.name, result))
        self.result = result
Eine Ausgabe ist nun zb.:
Calculating spam
radomnumber für spam ist 4
Calculating ham
radomnumber für ham ist 4
Calculating eggs
sum = 0
radomnumber für eggs ist 5
spam = 18
ham = 28
eggs = 40
Der Vorgang hat 5 sekunden gedauert, anstatt 4+4+5=13 sekunden :) Nur erschließst sich mir "sum" noch nicht... ist es gewollt, dass dort jedesmal sum=0 steht? Das wort sum lässt ja mutmaßen, dass es sich eigentlich um eine Summe aus den drei variablen handeln soll ^^

Die funktionsweise von map() habe ich denke ich verstanden. Sie sorgt dafür, dass nacheinander jeder der darauffolgenden Parameter and die Klasse Foo übergeben werden.

Die Aufgabe von "join()" ist mir noch nicht klar. Als erklärung fand ich:
"Die join()-Methode stellt sicher, dass das Hauptprogramm wartet, bis alle Threads terminiert haben. "
Aber was heißt terminiert? :D ich vermute mal, dass also gewartet wird, bis alle threads gestartet haben, oder fertig durchlaufen sind... vermutlich letzteres oder? Angenommen es ist letzteres. Das heißt dann also, dass eigentlich nun gewartet werden sollte, bis alle threads ihre Variablen vergeben haben und er dann mit print("sum=" weitergemacht werden sollte? Heißt das also, dass join() hier nicht korrekt funktioniert? Oder vermute ich komplett falsch und join() ist für was anderes da?

edit: nach kurzer Überlegund und Betrachtung der Ausgabe komme ich zu dem Schluss, dass join() nur wartet, bis jeder Thread gestartet ist, nicht bis sie fertig sind. Das erklärt also auch warum sum=0 ist, weil zu dem zeitpunkt noch keine werte vergeben sind. Und wir sehen in der Ausgabe ja, dass sum=0 direkt nach dem start des letzten Threads ausgeben wird.
Gibt es denn auch eine Funktion wie join(), die bis zum Ende jedes Threads wartet?

edit2:
und heißt das im Klartext, dass ich nun alles was ich so parallel machen machen will, in die run funktion schreiben muss? Auf mein Beispiel bezogen, würde ich dann z.b die werte 1,2 und 3 an die Klasse übergeben, damit die run funktion dann dafür sorgt, dass API 1,2 und 3 aufgerufen werden, richtig?

edit3:
es gibt ja noch irgendwelche "is_alive" sachen. Heißt das, dass ich threads eventuell noch "beenden" muss, oder brauche cih sowas in diesem Fall nicht?

fertig editiert ^^
BlackJack

@Serpens66: `join()` wartet auf das *Ende* des Threads. Da sollte also nicht 0 bei heraus kommen.

Und eventuell lohnt sich auch ein Blick auf `concurrent.futures` statt selber auf einer ”tieferen” Ebene Threads zu schreiben.

Man muss auch nicht unbedingt von `Thread` erben und eine `run()`-Methode implementieren wenn alles was in dieser Klasse die `__init__()` und die `run()`-Methode sind. Dann hat man nämlich eine Funktion unnötigerweise zu einer Klasse aufgeblasen. Man kann auch direkt aus `Thread` Objekte erstellen denen man eine Funktion und Argumente übergeben kann, die dann bei `start()` auf dem `Thread`-Objekt ausgeführt wird.
Serpens66
User
Beiträge: 259
Registriert: Montag 15. Dezember 2014, 00:31

BlackJack hat geschrieben:@Serpens66: `join()` wartet auf das *Ende* des Threads. Da sollte also nicht 0 bei heraus kommen.
Dass bei mir 0 rauskommt, könnte das an Python2 vs Python3 liegen? der Code von EyDu ist ja Python2, weshalb ich die "print ..." in "print(...)" umwandeln musste. Muss ich vllt noch irgendwas umändern, damit es korrekt funktioniert? Falls es eig richtig sein sollte, kommt bei euch bei Ausführung des Codes denn tatsächlich was anderes als Null raus?
BlackJack hat geschrieben: Und eventuell lohnt sich auch ein Blick auf `concurrent.futures` statt selber auf einer ”tieferen” Ebene Threads zu schreiben.
bin dabei auf diesen Thread gestoßen:
http://www.python-forum.de/viewtopic.php?f=1&t=31949
da steht ja einiges an Info dazu drin, allerdings auch einige Probleme. Habe es bisher nur überflogen, aber bevor ich mich weiter damit beschäftige:
Was ist denn benutzerfreundlicher? Die hier von EyDu vorgestellte Methode, oder concurrent.futures? Muss ich bei threading denn auch darauf achten, dass ich nicht ausversehen eine endlosSchleife von Prozessen generiere, oder kann das da garnicht passieren? Könnt ihr vllt einen kleinen vergleich mit Vor- und Nachteilen aufstellen/verlinken (hauptsächlich auf die Handhabung und effizienz bezogen)?
BlackJack

@Serpens66: Das bei Dir 0 heraus kommt liegt in der Tat daran das Du Python 3 verwendest. Viel Spass beim herausfinden warum das so ist. Ist eine schöne Übung ob man weiss mit welchen Werten da operiert wird und welche Eigenschaften und welches Verhalten die jeweils haben. Ich musste selbst zweimal hingucken, aber dann war es eigentlich sonnenklar was da passiert und warum die Schleife mit dem `join()` darin auf nichts wartet und weshalb bei der `sum()`-Funktion 0 heraus kommt, obwohl die `result`-Attribute der `Thread`-Objekte gar nicht den Wert 0 sondern `None` haben, was sich gar nicht aufaddieren lässt. :-)

Ob direktes verwenden von `threading` oder eine höhere API wie `concurrent.futures` benutzerfreundlicher ist, hängt davon ab ob sich das konkrete Problem mit `concurrent.futures` gut lösen lässt oder nicht. Die Probleme mit Prozessen hatte der OP von dem anderen Thema mit dem `multiprocessing`-Modul. Mit `concurrent.futures` kann man die Probleme zwar auch bekommen wenn man Prozesse statt Threads zum ausführen verwendet, aber Probleme kann man grundsätzlich mit so komplexen Sachen wie nebenläufiger Programmierung haben wenn man sich nicht an die ”Regeln” hält.

Die Dokumentation vom `multiprocessing` enthält eine Warnung und den Hinweis was man machen muss damit das mit den vielen Prozessen unter Windows nicht passiert, und das ist auch nichts exotisches sondern etwas das man eigentlich sowieso *immer* machen sollte: Module so schreiben das man sie ohne Seiteneffekte importieren kann.
Serpens66
User
Beiträge: 259
Registriert: Montag 15. Dezember 2014, 00:31

kann ich denn das Beispiel von snafu in Post 7 des threads (kann man irgendwie direkt auf Posts verlinken?) so übernehmen, also für meine Zwecke umschreiben und ist dann im Ergebnis "dasselbe" wie mit threading von EyDu?
Und da treten dann keine Probleme mit den Prozessen auf, da ich kein multiprocessing verwende, richtig?


das 2 zu 3 Problem hab ich jetzt mithilfe von 2to3 gelöst. man muss list(map(...)) schreiben. Da wäre ich vermutlich nie von selbst drauf gekommen. Gut es ist logisch, dass wenn eine for schleife auf threads zugreift, es ja verschiedene Elemente in threads geben muss. Aber warum "map" in Python2 nun sowas darstellt, aber in Python3 nicht mehr...

edit: wobei ich mit 2to3 auch wieder Probleme hatte. Ich hab leider schon wieder vergessen, wie ich es in meinem anderen Thread gemacht hatte: http://www.python-forum.de/viewtopic.php?f=2&t=35300
Wenn ich nämlich "2to3 new.py" eingeben (wenn die datei new heißt), dann kommt die fehlermeldung, dass 2to3 nicht bekannt ist. Ich muss halt immer "python" davor schreiben, wenn ich was starten will. Also schreibe ich "python 2to3 new.py" , auch hier kennt er 2to3 nicht. also schreibe ich "python 2to3.py new.py" dann meckert er, dass er eines der beiden nicht finden kann (weil sie sich nicht imselben Ordner befinden und ich zum starten ja immer in dem entprechenen Ordner sein muss). Also hab ich new.py in den PYthon34/Tools/Scripts Ordner verschoben und es nochmal probiert und dann gings endlich...
Ich schreib das auch deswegen hier auf, weil ich es im anderen Thread nicht gemacht habe, falls ich das nochmal vergesse und was umwandeln muss :D
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Serpens66 hat geschrieben:kann ich denn das Beispiel von snafu in Post 7 des threads (kann man irgendwie direkt auf Posts verlinken?)
Ja, der Link versteckt sich unter der "Seite" links neben dem "Verfasst" Zeitstempel, konkret ist das hier http://www.python-forum.de/viewtopic.ph ... 00#p243000
Serpens66
User
Beiträge: 259
Registriert: Montag 15. Dezember 2014, 00:31

@cofi: danke für den Hinweis :)


@all:
ich hab jetzt mal versucht das Beispiel von Snafu bezüglich concurrent.futures mit spam eggs usw. von EyDu zu befüllen. Es tut zumindest schonmal was es soll.. auch wenn man sicherlich noch viel optimieren müsste. uhrzeit() ist eine funktion, die die aktuelle Uhrzeit ausgibt, woran ich dann die zeit ablese, die der gesamte Durchlauf gedauert hat.

Code: Alles auswählen

def calculate(arg):
    print ("Calculating {}".format(arg))
    randomnumber = random.randint(1, 5)
    print("randomnumber für {} ist {}".format(arg, randomnumber))
    time.sleep(randomnumber)
    result = random.randint(1, 42)
    endresult = "{} = {}".format(arg, result)
    return endresult
 
def get_results():
    args = ("spam", "ham", "eggs")
    workers = 3
    with futures.ProcessPoolExecutor(max_workers=workers) as executor:
        for values in executor.map(calculate, args):
            print(values)
    #print ("sum =", sum(thread.result for thread in threads)) #hier steht noch der Threadteil, weiß grad nicht, wie ich auf die zuvor berechneten Werte zugreife?
    print(uhrzeit())
    return values # auch hier könnte man die zuvor berechneten werte ausgeben, wenn man möchte
 
if __name__=='__main__':
    print(uhrzeit())
    get_results()
Mal abgesehen von den bereits im Code angemerkten Dinge, arbeitet das so effizient? Ich habe mal die Zeiten verglichen. mit threading dauert der ganze Durchlauf genau so lange, wie die größte randomnumber, also sleep(randomnumber) ist.
Bei concurrent.futures dauert es so wie es hier steht (also mit 3 workern) 1-2 sekunden länger. Also falls man das nicht weiter optimieren kann, würde ich wohl zu threading tendieren.
Welchen Vorteil hat es eigentlich die Worker Zahl einstellen zu können? Bei Threading arbeiten vermutlich genau so viele Prozesse, wie gebraucht werden, oder? Und bei "concurrent.futures" muss man die Anzahl an Prozessen immer durch die workers angeben. Ich kann mir jetzt keinen Fall vorstellen, an dem es sinnvoll ist, weniger Worker einzustellen, als eigentlich nötig wären. Oder ist threading bei zuvielen Prozessen sonst überlastet, weshalb man lieber manuell weniger einstellt?
BlackJack

@Serpens66: Du vergleichst hier ein wenig Äpfel mit Birnen wenn Du im ersten Programm Threads verwendest und im zweiten dann Prozesse. Prozesse sind wesentlich teurer beim Starten und bei der Kommunikation der Werte zwischen den Prozessen weil die sich ja gerade keinen Adressraum teilen wie Threads.

Ebenfalls nicht wirklich sinvoll vergleichbar wird es unter Last wenn viele `Threads` gleichzeitig eine begrenzte Anzahl von Prozessoren belagern gegenüber so einem `Executor` der nur eine bestimmte Anzahl von Arbeitsthreads- oder Prozessen erstellt, idealerweise nicht so viele das es mehr Arbeiter gibt als Prozessoren, beziehungsweise Kerne, denn mehr als einer kann nicht wirklich eine CPU voll benutzen. Wenn es mehr Arbeiter als CPUs werden teilen die sich die CPU.

Last ist auch so ein Stichwort: `sleep()` ist das Gegenteil von Last. Man kann locker 50 Threads erzeugen die alle 5 Sekunden schlafen und das wird nach etwas mehr als 5 Sekunden fertig sein, weil man dafür so gut wie keine CPU braucht. Wenn Du aber 50 Threads erzeugst wo jeder einzelne alleine eine CPU 5 Sekunden lang von beschäftigen würde, dann geht die Zeit dafür eher so in Richtung 50*5/anzahl der Prozessoren(kerne) + Verwaltungsaufwand des Betriebssystems zum Umschalten zwischen den Threads. (Hier ist noch nicht das „global interpreter lock” (GIL) von CPython berücksichtigt, welches prozessorlastintensive Threads in Python sowieso extrem ausbremst.)
Antworten