Je suis donc verrouillé sur un interprète python 3.6.2 qui suit mon application de bureau.
Ce que je veux, c'est appeler une fonction asynchrone à partir d'une méthode ou d'une fonction synchronisée.
Lors de l'appel de la fonction python à partir de l'application de bureau, il doit s'agir d'une fonction normale qui ne peut être attendue.
Depuis l'application de bureau, je peux envoyer une liste d'URL, et ce que je veux, c'est renvoyer la réponse de chaque URL dans une affaire asynchrone.
voici mon essai j'ai marqué le SyntaxError que je ne sais pas contourner.
import fmeobjects
import asyncio
import aiohttp
import async_timeout
logger = fmeobjects.FMELogFile()
timeout = 10
class FeatureProcessor(object):
def __init__(self):
pass
def input(self, feature):
urls_and_coords = Zip(feature.getAttribute('_list{}._wms'),\
feature.getAttribute('_list{}._xmin'),\
feature.getAttribute('_list{}._ymin'),\
feature.getAttribute('_list{}._xmax'),\
feature.getAttribute('_list{}._ymax'))
-> SyntaxError: newfeature = await main(urls_and_coords)
self.pyoutput(newfeature)
def close(self):
pass
async def main(urls):
loop = asyncio.get_event_loop()
async with aiohttp.ClientSession(loop=loop) as session:
feature = loop.run_until_complete(fetch_all(session, urls, loop))
return feature
async def fetch_all(session, urls, loop):
results = await asyncio.gather(*[loop.create_task(fetch(session, url)) for url in urls])
return results
async def fetch(session, url):
with async_timeout.timeout(10):
async with session.get(url[0]) as response:
newFeature = fmeobjects.FMEFeature()
response_data = await response
newFeature.setAttribute('response', response_data)
newFeature.setAttribute('_xmin',url[1])
newFeature.setAttribute('_xmax',url[2])
newFeature.setAttribute('_ymin',url[3])
newFeature.setAttribute('_ymax',url[4])
return newFeature
J'ai essayé d'apporter ces modifications: import fme import fmeobjects import asyncio import aiohttp import async_timeout logger = fmeobjects.FMELogFile ()
class FeatureProcessor(object):
def __init__(self):
pass
def input(self, feature):
urls_and_coords = Zip(feature.getAttribute('_list{}._wms'),\
feature.getAttribute('_list{}._xmin'),\
feature.getAttribute('_list{}._ymin'),\
feature.getAttribute('_list{}._xmax'),\
feature.getAttribute('_list{}._ymax'))
loop = asyncio.get_event_loop()
result = loop.run_until_complete(main(loop, urls_and_coords))
#feature.setAttribute('result',result)
self.pyoutput(feature)
def close(self):
pass
async def main(loop, urls):
async with aiohttp.ClientSession(loop=loop) as session:
return await fetch_all(session, urls, loop)
async def fetch_all(session, urls, loop):
results = await asyncio.gather(*[loop.create_task(fetch(session, url)) for url in urls])
return results
async def fetch(session, url):
with async_timeout.timeout(10):
async with session.get(url[0]) as response:
#newFeature = fmeobjects.FMEFeature()
response = await response
#newFeature.setAttribute('response', response_data)
#newFeature.setAttribute('_xmin',url[1])
#newFeature.setAttribute('_xmax',url[2])
#newFeature.setAttribute('_ymin',url[3])
#newFeature.setAttribute('_ymax',url[4])
return response, url[1], url[2], url[3], url[4]
mais maintenant je me retrouve avec cette erreur:
Python Exception <TypeError>: object ClientResponse can't be used in 'await'
expression
Traceback (most recent call last):
File "<string>", line 20, in input
File "asyncio\base_events.py", line 467, in run_until_complete
File "<string>", line 29, in main
File "<string>", line 33, in fetch_all
File "<string>", line 41, in fetch
TypeError: object ClientResponse can't be used in 'await' expression
Vous utiliseriez une boucle d'événement pour exécuter la fonction asynchrone jusqu'à son terme:
newfeature = asyncio.get_event_loop().run_until_complete(main(urls_and_coords))
(Cette technique est déjà utilisée dans main
. Et je ne sais pas pourquoi, puisque main
est async
vous pourriez/devriez utiliser await fetch_all(...)
là-bas. )
La réponse @deceze est probablement la meilleure que vous puissiez faire dans Python 3.6. Mais dans Python 3.7, vous pouvez directement utiliser asyncio.run
de la manière suivante:
newfeature = asyncio.run(main(urls))
Il créera, gérera et fermera correctement un event_loop
.