Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to call a async function from a synchronized code Python

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 
like image 797
Paal Pedersen Avatar asked Aug 09 '18 08:08

Paal Pedersen


People also ask

How do I call a function asynchronously in Python?

To run an async function (coroutine) you have to call it using an Event Loop. Event Loops: You can think of Event Loop as functions to run asynchronous tasks and callbacks, perform network IO operations, and run subprocesses. Example 1: Event Loop example to run async Function to run a single async function: Python3.

Can we call async method in sync method?

Solution A If you have a simple asynchronous method that doesn't need to synchronize back to its context, then you can use Task. WaitAndUnwrapException : var task = MyAsyncMethod(); var result = task. WaitAndUnwrapException();

Can async function call non-async function in Python?

Conversely you absolutely can call non-async code from async-code, in fact it's easy to do so. But if a method/function call might “block” (ie. take a long time before it returns) then you really shouldn't. As you can see the counter has paused during the whole time it takes to make the HTTP request.

How do you call an asynchronous function?

Inside an async function, you can use the await keyword before a call to a function that returns a promise. This makes the code wait at that point until the promise is settled, at which point the fulfilled value of the promise is treated as a return value, or the rejected value is thrown.


2 Answers

@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.

like image 161
Francis Colas Avatar answered Oct 05 '22 18:10

Francis Colas


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.)

like image 30
deceze Avatar answered Oct 05 '22 18:10

deceze