【问题标题】:Asyncio run a task that return a resultAsyncio 运行返回结果的任务
【发布时间】:2021-06-08 22:17:46
【问题描述】:

我来自 C# 背景,Python 的 Asyncio 库让我很困惑。

我已经阅读了以下12,但我仍然不清楚 asyncio 的使用。

我正在尝试用python制作一个异步网站scraper

async def requestPage(url):
    request = requests.get(url, headers=headers)
    soup = BeautifulSoup(request.content, 'html.parser')
    return soup


async def main():

    #****** How do I run an async task and store its result to use in another task?
    index_soup = asyncio.ensure_future(requestPage(index_url))
    res = asyncio.gather(index_soup)
    currency_urls = res.select('a[href^="/currencies"]')

    print(currency_urls)


loop = asyncio.get_event_loop()

try:
    
    loop.run_until_complete(main())
finally:
    loop.close() 

【问题讨论】:

  • 这永远不会真正异步,因为请求不是异步的。您可能需要考虑改用 aiohttp 之类的库。

标签: python python-asyncio


【解决方案1】:

由于requests库不是异步的,你可以使用run_in_executor方法,这样就不会阻塞正在运行的线程。结果,您可以将requestPage 定义为常规函数并在main 函数中调用它,如下所示:

res = await asyncio.gather(loop.run_in_executor(None, requestPage, url)

阻塞函数将在单独的执行器中运行,而控制将返回给事件循环。

或者您可以尝试使用异步 HTTP 客户端库,例如 aiohttp

【讨论】:

    【解决方案2】:

    好的,我想我找到了一个基本的解决方案。

    async def requestPage(url):
        request = requests.get(url, headers=headers)
        soup = BeautifulSoup(request.content, 'html.parser')
        return soup
    
    
    async def getValueAsync(func, param):
        # Create new task
        task = asyncio.ensure_future(func(param))
        # Execute task. This returns a list of tasks
        await asyncio.gather(task)
        # Get result from task
        return task.result()
    
    async def main():
        soup = await getValueAsync(requestPage, index_url)
        print(val.encode("utf-8"))
    
    
    loop = asyncio.get_event_loop()
    
    try:
    
        loop.run_until_complete(main())
    finally:
        loop.close() 
    

    我写了一个包装器,它允许我异步调用函数并存储结果。

    【讨论】:

    • 这段代码有效地执行了await gather(ensure_future(requestPage(url)))。这与简单的await requestPage(url) 之间没有区别 - gather 旨在等待 多个 任务。此外,您不需要额外调用task.result()await 将立即返回结果。最后,要使代码真正异步,您需要使用像aiohttp 这样的库,而不是requests。一条经验法则是:如果您的 async def 不等待任何内容,则它不是异步的,并且(就行为而言)也可以是普通的 def
    • @user4815162342 感谢您的反馈。我以为我首先必须创建一个任务并执行它。那你能向我解释一下 ensure_future 的用法吗?
    • ensure_future 在您需要实际的未来对象时很有用,例如所以你可以打电话给add_done_callback 或类似的。在您的情况下,您通过获取任务对象一无所获,因为您立即等待它。
    • 啊。公平的比较是 ensure_future 类似于 javascript 承诺吗?例如,我可以将执行称为任务,然后再决定如何处理结果?
    猜你喜欢
    • 2021-10-07
    • 1970-01-01
    • 2019-04-13
    • 1970-01-01
    • 2017-06-02
    • 1970-01-01
    • 2020-08-10
    • 2021-02-21
    • 1970-01-01
    相关资源
    最近更新 更多