đ · Python: NebenlĂ€ufigkeit
Wenn man ein Programm schreiben möchte, das mehrere Dinge gleichzeitig tun können soll, dann stöĂt man frĂŒher oder spĂ€ter auf das Konzept der NebenlĂ€ufigkeit. Ich werde mich in diesem Guide auf Python und speziell
asyncio
beschrÀnken, da das gesamte Thema gar nicht in einem einzigen Post erklÀrt werden könnte!
NebenlÀufigkeit vs. Parallelismus
Zu Beginn sollte ich vielleicht den Begriff nochmal etwas genauer einschrÀnken:
Wenn ein Programm mehrere Prozessoren (oder Prozessorkerne) fĂŒr die AusfĂŒhrung von verschiedenen Dingen benutzt, dann spricht man von paralleler Verarbeitung. Das Programm kann wirklich mehrere Dinge gleichzeitig und völlig unabhĂ€ngig voneinander tun.
Mit der NebenlĂ€ufigkeit, um die es in diesem Guide gehen soll, bezeichnet man Programme, die auf einem einzigen Prozessor laufen (der also nur eine Anweisung auf einmal ausfĂŒhren kann) und scheinbar gleichzeitig verschiedene Dinge tun. In Wirklichkeit wechseln sich die Prozesse immer wieder ab und erzeugen dadurch den Eindruck der Gleichzeitigkeit.19 Replies
asyncio
und kooperatives Multitasking
asyncio
ist eine Python Bibiliothek, die NebenlÀufigkeit in Form von kooperativem Multitasking ermöglicht. Das bedeutet, dass nicht das Betriebssystem bzw. ein Event Scheduler entscheidet, wann welcher Prozess laufen darf, sondern dass die Prozesse von sich aus die CPU "freigeben".
In asyncio
wird das ĂŒber das SchlĂŒsselwort await
gelöst: Sobald eine Funktion mit await
aufgerufen wird, hat ein anderer Prozess (aus der asyncio
Event Loop) die Möglichkeit zu laufen, bis er selber wieder eine Funktion mit await
aufruft. In der Regel sind diese Funktionen solche, die (verhĂ€ltnismĂ€Ăig fĂŒr einen Prozessor) lange auf eine "Antwort" warten mĂŒssen, wie beispielsweise Netzwerk- oder Speicherzugriffe. Sobald die Antwort da ist, können die Prozesse wieder den Prozessor "bekommen" und weiterlaufen.
Das zweite wichtige SchlĂŒsselwort von asyncio
ist async
: Dieses steht vor allen Funktionsdefinitionen, die in irgendeiner Form await
benutzen möchten, oder vor bestimmten Python-SchlĂŒsselwörtern wie with
oder for
(die nÀmlich ansonsten das "Freigeben" durch await
-Aufrufe verhindern könnten).
Besonderheiten bei der Programmierung mit asyncio
Um die NebenlÀufigkeit möglichst effektiv zu machen, muss man ein paar Sachen bei der Entwicklung von Programmen mit asyncio
beachten.
Zum Teil muss man andere Bibiliotheken als gewöhnlich benutzen, die zwar dieselbe FunktionalitÀt haben, aber mit NebenlÀufigkeit. Das ist beispielsweise so bei aiohttp
und aiomysql
. Viele beliebte Bibiliotheken haben asyncio
aber inzwischen auch schon direkt enthalten; Beispiele dafĂŒr sind Django
und websockets
.
Weiterhin muss das Programm gÀnzlich gut (bzw. "kooperierend" via await
) geschrieben sein, damit die NebenlĂ€ufigkeit funktioniert. Da die Event Loop keine Möglichkeit hat einen Prozess frĂŒher zu beenden, kann sich ein Programm durch kleine Fehler schnell schon aufhĂ€ngen.
Zu guter Letzt: Bei rechenintensiven Prozessen ist asyncio
keine gute Lösung, da es keine "Antworten" gibt, auf die gewartet werden kann. TatsĂ€chlich verlangsamt sich die ProgrammausfĂŒhrung in diesem Fall sogar, da das wechseln zwischen den Prozessen zusĂ€tzliche Zeit verbraucht.
--
Feedback, Fragen und Kommentare gerne in den Post hierrunter schreiben! :)
Idee: @Fabio3323 (ich hoffe, du meintest asyncio
mit deinem Vorschlag xD)
Quellen:
- https://realpython.com/python-concurrency/
- https://en.wikipedia.org/wiki/Concurrency_(computer_science)
- https://en.wikipedia.org/wiki/Computer_multitasking
- https://docs.python.org/3/library/asyncio.html
- https://stackoverflow.com/questions/49005651/how-does-asyncio-actually-work/51116910#51116910
- https://realpython.com/python-async-features/
- https://stackoverflow.com/questions/67092070/why-do-we-need-async-for-and-async-with
- https://github.com/timofurrer/awesome-asyncio
(Als nĂ€chstes plane ich aktuell den Unterschied zwischen discord.py und py-cord zu beschreiben. Allerdings wird die Recherche fĂŒr diesen Guide deutlich lĂ€nger dauern und ich muss dafĂŒr zuerst die Zeit finden ^^)Ich meine async Loops
Oh whoops xD
Ich denke mal du meinst auch nicht die
async for
Loops, sondern nebenlÀufige Aufgaben innerhalb von Loops. Also mit gather
oder Tasks
etc.
Stimmt das diesmal? xD Bevor ich wieder das Falsche beschreibe...
Ich werds dann einfach direkt unter den Rest vom Post schreiben, gehört ja auch noch zum ThemaYes. Warte ich schick dir ein code example:
async def funktion(bot, ..., when: datetime.datetime):
wo ist der code? xD
Dieses async def Funktion und dann halt mit diesem when
aber was daran hat mit loops zu tun? das versteh ich nicht
ich sehe nur eine async definierte funktion, die ein argument namens "when" hat
ich werd die erklÀrung aber noch schreiben, sobald ich die zeit finde
Jop
Das wĂ€ren eher Scheduler die etwas zu einem bestimmten Zeitpunkt ausfĂŒhren aber keine Loops.
Bissl falsch dargestellt. Sowas wie apscheduler oder aioscheduler.
Sicher?
naja wozu sollte man sonst
when
(wann) angeben?
MĂŒsstest du dem @Laqco schon genauer erklĂ€ren was du meinst.Ich weiĂ es selber nicht genau. Ein Kollege hat mir das erklĂ€rt aber mehr verstehe ich auch nicht :HAhaa:
https://discord.com/channels/725390391309893722/1104474089801920562
Dann poste besser so nen code, wenn du ihn nicht verstehst. Dann kannste es anderen ja auch nicht genauer erklÀren? :Thonk:
macht wenig sinn xD
Das meine ich
https://i.ibb.co/BgwJYDF/image.png Damit Laqco das auch nachverfolgen kann, der ist ja nicht auf dem Server.
Wolltest ja eigentlich von Ihm ne ErklÀrung.
Also das ist eher das task feature von asyncio. Das man mit einem Loop ĂŒber alle daten der db geht, um daten xy abzufragen fĂŒr bot neustart ist ja irgendwie logisch.
irgendwoher mĂŒssen die daten ja kommen
(lol ich wusste nicht dass es temporĂ€re server joins gibt fĂŒr sowas, das ist ja mal ein nices feature!)
soweit ich das grad sehe ist das nur eine random funktion, die nichts mit asyncio zu tun hat. das eigentliche thema sind ja tasks
ich werde einen nachtrag zu tasks schreiben
hatte ich ja hier schon vermutet
Okok
aber danke @Martin B. ă fĂŒr die aufklĂ€rung xD ich war mir tatsĂ€chlich bis jetzt nicht ganz sicher
Wow, ich finde mal wieder etwas Zeit đ€Ż - jetzt muss ich auch mein altes Versprechen einhalten...
Mit
asyncio.gather
kannst du mehrere coroutines (async
Funktionen) "asynchron" (pun intended) ausfĂŒhren lassen und alle "Ergebnisse" (z.B. return-Werte) in einem Tupel gesammelt zurĂŒck bekommen. Intern erzeugt das fĂŒr coroutines nur einen Task
und hat keine (wichtige) weitere FunktionalitÀt.
Coroutines kann man nicht wie normale Funktionen einfach ausfĂŒhren. Stattdessen muss man sie in einer event loop "anmelden".
- Die einfache Methode (auĂer await
) ist asyncio.run()
: Die coroutine wird der event loop hinzugefĂŒgt und dann ein Mal ausgefĂŒhrt.
- Man kann auch mit asyncio.create_task()
einen Task
erstellen, der die coroutine ausfĂŒhrt. Einen Task
kann man starten, stoppen, fortsetzen, auch wiederholt starten; man kann Tasks
gruppieren, sie unter einem bestimmten Kontext ausfĂŒhren. Der Hauptvorteil liegt dabei vermutlich auf dem ersten Punkt: Man kann nĂ€mlich mehrere Tasks
nacheinander starten (einfach das Objekt awaiten: await task
; oder gather
benutzen), die dann nebenlĂ€ufig ausgefĂŒhrt werden.
Quellen:
- https://docs.python.org/3/library/asyncio-task.html
ich weiĂ, es ist spĂ€t, aber besser spĂ€t als nie đ
Huch haha