问题
So I'm locked to a python 3.6.2 interpreter that follows my desktop application.
What I want is to call an async function from a synchronized method or function.
When calling the python function from the desktop application it has to be a normal function which can not be awaited.
From the desktop application I am able to send a list of urls, and what I want is to send back response from every url in an async matter.
here is my try I've marked the SyntaxError which I don't know how to bypass.
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
I have tried making these changes: 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]
but now I end up with this error:
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
回答1:
You would use an event loop to execute the asynchronous function to completion:
newfeature = asyncio.get_event_loop().run_until_complete(main(urls_and_coords))
(This technique is already used inside main
. And I'm not sure why, since main
is async
you could/should use await fetch_all(...)
there.)
回答2:
@deceze answer is probably the best you can do in Python 3.6. But in Python 3.7, you could directly use asyncio.run in the following way:
newfeature = asyncio.run(main(urls))
It will properly create, handle, and close an event_loop
.
来源:https://stackoverflow.com/questions/51762227/how-to-call-a-async-function-from-a-synchronized-code-python