J'ai une fonction asynchrone et j'ai besoin de courir avec apscheduller toutes les N minutes. Il y a un code python ci-dessous)
URL_LIST = ['<url1>',
'<url2>',
'<url2>',
]
def demo_async(urls):
"""Fetch list of web pages asynchronously."""
loop = asyncio.get_event_loop() # event loop
future = asyncio.ensure_future(fetch_all(urls)) # tasks to do
loop.run_until_complete(future) # loop until done
async def fetch_all(urls):
tasks = [] # dictionary of start times for each url
async with ClientSession() as session:
for url in urls:
task = asyncio.ensure_future(fetch(url, session))
tasks.append(task) # create list of tasks
_ = await asyncio.gather(*tasks) # gather task responses
async def fetch(url, session):
"""Fetch a url, using specified ClientSession."""
async with session.get(url) as response:
resp = await response.read()
print(resp)
if __name__ == '__main__':
scheduler = AsyncIOScheduler()
scheduler.add_job(demo_async, args=[URL_LIST], trigger='interval', seconds=15)
scheduler.start()
print('Press Ctrl+{0} to exit'.format('Break' if os.name == 'nt' else 'C'))
# Execution will block here until Ctrl+C (Ctrl+Break on Windows) is pressed.
try:
asyncio.get_event_loop().run_forever()
except (KeyboardInterrupt, SystemExit):
pass
Mais quand j'ai essayé de le lancer, j'ai les informations d'erreur suivantes
Job "demo_async (trigger: interval[0:00:15], next run at: 2017-10-12 18:21:12 +04)" raised an exception.....
..........\lib\asyncio\events.py", line 584, in get_event_loop
% threading.current_thread().name)
RuntimeError: There is no current event loop in thread '<concurrent.futures.thread.ThreadPoolExecutor object at 0x0356B150>_0'.
Pourriez-vous s'il vous plaît m'aider avec cela? Python 3.6, APScheduler 3.3.1,
Il suffit de passer fetch_all
À scheduler.add_job()
directement. Le planificateur asyncio prend en charge les fonctions de coroutine en tant que cibles de travail.
Si l'appelable cible est pas une fonction de coroutine, il sera exécuté dans un thread de travail (pour des raisons historiques), d'où l'exception.
Dans votre def demo_async(urls)
, essayez de remplacer:
loop = asyncio.get_event_loop()
avec:
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
La chose importante qui n'a pas été mentionnée est la raison pour laquelle l'erreur se produit. Pour moi personnellement, il est aussi important de savoir pourquoi l'erreur se produit que de résoudre le problème.
Jetons un coup d'œil à l'implémentation du get_event_loop
De BaseDefaultEventLoopPolicy
:
class BaseDefaultEventLoopPolicy(AbstractEventLoopPolicy):
...
def get_event_loop(self):
"""Get the event loop.
This may be None or an instance of EventLoop.
"""
if (self._local._loop is None and
not self._local._set_called and
isinstance(threading.current_thread(), threading._MainThread)):
self.set_event_loop(self.new_event_loop())
if self._local._loop is None:
raise RuntimeError('There is no current event loop in thread %r.'
% threading.current_thread().name)
return self._local._loop
Vous pouvez voir que la self.set_event_loop(self.new_event_loop())
n'est exécutée que si toutes les conditions ci-dessous sont remplies:
self._local._loop is None
- _local._loop
N'est pas défininot self._local._set_called
- set_event_loop
N'a pas encore été appeléisinstance(threading.current_thread(), threading._MainThread)
- le thread actuel est le principal (ce n'est pas vrai dans votre cas)Par conséquent, l'exception est déclenchée, car aucune boucle n'est définie dans le thread actuel:
if self._local._loop is None:
raise RuntimeError('There is no current event loop in thread %r.'
% threading.current_thread().name)
Comme cette question continue d'apparaître sur la première page, j'écrirai mon problème et ma réponse ici.
J'avais un RuntimeError: There is no current event loop in thread 'Thread-X'.
En utilisant flask-socketio et Bleak .
Edit: eh bien, j'ai refactoré mon fichier et créé un cours.
J'ai initialisé la boucle dans le constructeur, et maintenant tout fonctionne bien:
class BLE:
def __init__(self):
self.loop = asyncio.get_event_loop()
# function example, improvement of
# https://github.com/hbldh/bleak/blob/master/examples/discover.py :
def list_bluetooth_low_energy(self) -> list:
async def run() -> list:
BLElist = []
devices = await bleak.discover()
for d in devices:
BLElist.append(d.name)
return 'success', BLElist
return self.loop.run_until_complete(run())
Usage:
ble = path.to.lib.BLE()
list = ble.list_bluetooth_low_energy()
Réponse originale:
La solution était stupide. Je n'ai pas fait attention à ce que j'ai fait, mais j'ai déplacé certains import
d'une fonction, comme ceci:
import asyncio, platform
from bleak import discover
def listBLE() -> dict:
async def run() -> dict:
# my code that keep throwing exceptions.
loop = asyncio.get_event_loop()
ble_list = loop.run_until_complete(run())
return ble_list
J'ai donc pensé que je devais changer quelque chose dans mon code et j'ai créé une nouvelle boucle d'événement en utilisant ce morceau de code juste avant la ligne avec get_event_loop()
:
loop = asyncio.new_event_loop()
loop = asyncio.set_event_loop()
À ce moment-là, j'étais plutôt heureux, car j'avais une boucle en marche.
Mais ne répond pas. Et mon code s’appuyait sur un délai d’attente pour renvoyer des valeurs, c’était donc très mauvais pour mon application.
Il m'a fallu près de deux heures pour comprendre que le problème était le import
, et voici mon code (de travail):
def list() -> dict:
import asyncio, platform
from bleak import discover
async def run() -> dict:
# my code running perfectly
loop = asyncio.get_event_loop()
ble_list = loop.run_until_complete(run())
return ble_list
Utilisez asyncio.run()
au lieu d'utiliser directement la boucle d'événement. Il crée une nouvelle boucle et la ferme lorsque vous avez terminé.
Voici à quoi ressemble le 'run':
if events._get_running_loop() is not None:
raise RuntimeError(
"asyncio.run() cannot be called from a running event loop")
if not coroutines.iscoroutine(main):
raise ValueError("a coroutine was expected, got {!r}".format(main))
loop = events.new_event_loop()
try:
events.set_event_loop(loop)
loop.set_debug(debug)
return loop.run_until_complete(main)
finally:
try:
_cancel_all_tasks(loop)
loop.run_until_complete(loop.shutdown_asyncgens())
finally:
events.set_event_loop(None)
loop.close()