Ersatz für asyncio.get_event_loop nach python 3.10?
Verfasst: Mittwoch 8. Juni 2022, 02:27
Hallo,
Ich nutze aktuell folgenden Aufbau (exemplarischer code, der aber auch ausgeführt werden kann):
Kurz erklärt soll hier 5 mal unabhängig voneinander und möglichst zeitgleich die funktion "do_sth_simultan" laufen. Diese macht sowohl cpu intensive aufgaben, als auch API calls. Durch die cpu intensiven Aufgaben macht es keinen Sinn diese 5 gleichzeitigen Aufrufe mit asyncio durchzuführen, während es aber definitiv sinnvoll ist die API calls mit asyncio zu machen. Der obige Aufbau ist der nach meinem Wissen beste Weg das Ziel zu erreichen (noch besser wären natürlich untersch. Prozesse für die 5 Aufrufe anstelle von Threads, aber das wird wohl sonst viel zu kompliziert).
Warum schreibe ich hier:
Weil in der Doku vom Event Loop python 3.10 * steht, dass get_event_loop bald gestrichen wird und dann nur ein Zeiger auf get_running_loop ist, wobei get_running_loop wohl nur innerhalb einer coroutine funktioniert. Dh. mein obiger code würde mit get_event_loop nicht mehr funktionieren.
Mein erster Gedanke war "dann ersetze ich meine get_event_loop Zeile halt einfach mit new_event_loop". Doch dann viel mir auf, dass auf die neuste Version vom "python-telegram-bot" ** und evlt. noch andere Module neuerdings auf asyncio setzen. Und diese verwenden logischerweise auch get_event_loop, ebenfalls außerhalb einer coroutine.
Für meine Verwendung von "asyncio.run_coroutine_threadsafe" brauche ich ja zwingend den loop, dh. ein Wechsel auf das empfohlene "asyncio.run()" kommt daher garnicht in Frage. Und soweit ich weiß sollte man pro Prozess nur einen loop verwenden, weshalb es natürlich wichtig wäre, dass mein oben generierter loop auch von telegram oder sonstigen Modulen verwendet wird.
Aktuell ist mit get_event_loop genau das möglich (nimmt existierenden loop oder erstellt einen neuen). Aber sobald das gestrichen wird wüsste ich nicht, wie das am Ende noch funktionieren soll?!
Frage:
Also warum wird get_event_loop gestrichen? Und wie ersetzt man diese doch extrem wichtige Funktionalität, wenn man den loop als objekt benötigt?
Diese Frage bitte gerne auch ohne Bezug zu meinem Code und nur den noch vorhandenen Funktionen wie run_coroutine_threadsafe und anderen Funktionen die einen loop weiterhin benötigen, beantworten, falls mein Code nur wieder für Entsetzen sorgt.
* https://docs.python.org/3/library/async ... tloop.html
** https://github.com/python-telegram-bot/ ... ication.py
Ich nutze aktuell folgenden Aufbau (exemplarischer code, der aber auch ausgeführt werden kann):
Code: Alles auswählen
import time
import asyncio
import aiohttp
from random import randint
import concurrent.futures
import threading
# from telegrambot import TelegramBot
class Sample:
def __init__(self,async_loop,tele):
self.async_loop = async_loop
self.async_session = None
self.tele = tele
def main(self):
future = asyncio.run_coroutine_threadsafe(self.init_async_session(self.async_loop), self.async_loop)
future.result()
print("start 5 threads for do_sth_simultan")
pool = concurrent.futures.ThreadPoolExecutor(5)
futures = []
params = [1,2,3,4,5]
for param in params: # call the function with 5 different settings that should run the same time.
futures.append(pool.submit(self.do_sth_simultan,param))
for future in futures: # Ich weiss, dass der aufrufende Thread dadurch jetzt wartend laeuft, das ist nicht Thema
future.result()
# shut down:
print("shutting down")
future = asyncio.run_coroutine_threadsafe(self.stop_async_session(), self.async_loop)
future.result()
self.async_loop.call_soon_threadsafe(self.async_loop.stop)
def do_sth_simultan(self,param):
for times in range(2): # run until closed, but for simulation run 2 times
time.sleep(randint(param,5)) # simulate some calculation
futures = []
for i in range(10): # doing 10 api calls with help of async
futures.append(asyncio.run_coroutine_threadsafe(self.async_api_call(param), self.async_loop))
results = []
for future in futures:
results.append(future.result())
# self.tele.updater.bot.send_message("userid","blah") # send some message via telegram
time.sleep(randint(param,5)) # simulate some calculation with results
#### Async API stuff:
async def init_async_session(self,async_loop):
self.async_session = aiohttp.ClientSession() # can only be initialized within async
async def stop_async_session(self):
if self.async_session is not None:
await self.async_session.close()
async def async_api_call(self,param):
response = await asyncio.sleep(randint(1,5))# -> simulate: await self.async_session.request(...)
return response
if __name__ == '__main__':
async_loop = asyncio.get_event_loop() # erstellt neuen loop, wenns noch keinen gibt. nach python 3.10 evlt new_event_loop nehmen?
tele = None # simulate TelegramBot("Token") # python-telegram-bot. is also using asyncio, currently with get_event_loop
S = Sample(async_loop=async_loop,tele=tele)
thread = threading.Thread(target=S.main)
thread.setDaemon(True) # do not block
thread.start()
async_loop.run_forever()
Warum schreibe ich hier:
Weil in der Doku vom Event Loop python 3.10 * steht, dass get_event_loop bald gestrichen wird und dann nur ein Zeiger auf get_running_loop ist, wobei get_running_loop wohl nur innerhalb einer coroutine funktioniert. Dh. mein obiger code würde mit get_event_loop nicht mehr funktionieren.
Mein erster Gedanke war "dann ersetze ich meine get_event_loop Zeile halt einfach mit new_event_loop". Doch dann viel mir auf, dass auf die neuste Version vom "python-telegram-bot" ** und evlt. noch andere Module neuerdings auf asyncio setzen. Und diese verwenden logischerweise auch get_event_loop, ebenfalls außerhalb einer coroutine.
Für meine Verwendung von "asyncio.run_coroutine_threadsafe" brauche ich ja zwingend den loop, dh. ein Wechsel auf das empfohlene "asyncio.run()" kommt daher garnicht in Frage. Und soweit ich weiß sollte man pro Prozess nur einen loop verwenden, weshalb es natürlich wichtig wäre, dass mein oben generierter loop auch von telegram oder sonstigen Modulen verwendet wird.
Aktuell ist mit get_event_loop genau das möglich (nimmt existierenden loop oder erstellt einen neuen). Aber sobald das gestrichen wird wüsste ich nicht, wie das am Ende noch funktionieren soll?!
Frage:
Also warum wird get_event_loop gestrichen? Und wie ersetzt man diese doch extrem wichtige Funktionalität, wenn man den loop als objekt benötigt?
Diese Frage bitte gerne auch ohne Bezug zu meinem Code und nur den noch vorhandenen Funktionen wie run_coroutine_threadsafe und anderen Funktionen die einen loop weiterhin benötigen, beantworten, falls mein Code nur wieder für Entsetzen sorgt.
* https://docs.python.org/3/library/async ... tloop.html
** https://github.com/python-telegram-bot/ ... ication.py