web-dev-qa-db-fra.com

Comment appeler une fonction asynchrone à partir d'un code synchronisé Python

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
9
Paal Pedersen

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

10
deceze

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.

9
Francis Colas