【问题标题】:Running two Async Functions where one returns data and another returns Nothing using Asyncio使用 Asyncio 运行两个异步函数,其中一个返回数据,另一个返回 Nothing
【发布时间】:2022-08-13 22:59:55
【问题描述】:

假设我有一些要异步运行的任务。

我想异步进行一系列 4 个 API 调用,但我也想有另一个异步函数检查我的会话状态。

使用asyncio 我尝试过:

import aiohttp
import asyncio
async def make_request():
    async with aiohttp.ClientSession() as session:
        async with session.get(\'http://httpbin.org/get\') as resp:
            print(resp.status)
            print(await resp.text())

    return resp

async def say_hello():
    print(\"Hello\")

async def main():

    tasks = []
    for i in range(4):
        tasks.append(asyncio.create_task(make_request()))

    results = await asyncio.gather(*tasks, say_hello(),)
    
if __name__ == \"__main__\":
    event_loop = asyncio.get_event_loop()
    event_loop.run_until_complete(main())

实际上,我的say_hello() 正在检查状态并更新类属性(会话),同时根据设定的时间频率发出请求。我如何才能在make_request() 中完成与我的实际 API 调用执行一起运行的这个“状态”函数,它返回一个响应对象,我稍后在完成时处理该对象。

  • 据我所知,您应该将() 添加到make_request,即tasks.append(asyncio.create_task(make_request()))
  • @bzu 好的,是的,这是一个错字,但不是我的问题。我希望结果不包括从say_hello() 返回的None 结果,或者我只需要一个额外的过程来从产生的results 中过滤掉None
  • 如果您不想在结果列表中出现 None,只需将其丢弃即可。在 main 结束前添加一行 results = [a for a in results if a is not None]。然而,Andrej Kessaly 的回答是一个更好的解决方案。

标签: python asynchronous async-await python-asyncio aiohttp


【解决方案1】:

我认为您应该以不同的方式构建您的代码。让while True: 在say_hello() 中循环,然后将await asyncio.sleep(N) 放在那里。将say_hello() 移出asyncio.gather:

import aiohttp
import asyncio


async def make_request():
    async with aiohttp.ClientSession() as session:
        async with session.get("http://httpbin.org/get") as resp:
            resp.status
            await resp.text()
            await asyncio.sleep(2)  # sleep here artificially

    return resp


async def say_hello():
    while True:
        # update session here
        # ...
        await asyncio.sleep(1)
        print("Hello")


async def main():

    tasks = []
    for i in range(4):
        tasks.append(asyncio.create_task(make_request()))

    asyncio.create_task(say_hello())

    results = await asyncio.gather(
        *tasks,
    )

    print(results)


if __name__ == "__main__":
    event_loop = asyncio.get_event_loop()
    event_loop.run_until_complete(main())

编辑:全局会话示例:

import aiohttp
import asyncio

session = None
headers = {"MySessionHeader": "0"}

# limit concurrency of connections to 2
sem = asyncio.Semaphore(2)


async def make_request():
    async with sem, session.get(
        "http://httpbin.org/get", headers=headers
    ) as resp:
        resp.status
        print(await resp.text())
        await asyncio.sleep(2)  # sleep here artificially
    return resp


async def update_headers():
    count = 1
    while True:
        await asyncio.sleep(1)
        # update headers of session:
        # eg. update cookies/headers
        headers["MySessionHeader"] = str(count)
        count += 1


async def main():
    global session
    session = aiohttp.ClientSession()

    tasks = []
    for i in range(24):
        tasks.append(asyncio.create_task(make_request()))

    asyncio.create_task(update_headers())

    results = await asyncio.gather(
        *tasks,
    )

    print(results)

    await session.close()


if __name__ == "__main__":
    event_loop = asyncio.get_event_loop()
    event_loop.run_until_complete(main())

【讨论】:

  • 所以asyncio.create_task(say_hello()) 将首先开始异步运行,然后收集将接收请求的任务?我对asyncio 很陌生,没有意识到你可以做到这一点。我认为您必须将您的任务放在gather 中。这很棒!又一想。如果我在一个类中执行所有这些操作并且正在更新像self.session 这样的属性,那么这里是否需要担心竞争条件?例如。如果我的make_requests() 正在使用self.session 和say_hello() 正在刷新self.session
猜你喜欢
  • 2019-11-11
  • 2021-04-14
  • 1970-01-01
  • 2021-11-26
  • 1970-01-01
  • 1970-01-01
  • 2021-10-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多