aiohttp.ClientSession()对象的.get()方法为何即使是异步,也会按顺序返回结果?

huangapple go评论61阅读模式
英文:

Why does aiohttp.ClientSession() object .get() Method Return Results In Order Even Though It Is Asynchronous?

问题

I found myself wondering if aiohttp.ClientSession() would return results sequentially because it was supposed to call a server many times, and then wait for all of the replies to arrive. I was expecting the results to be returned in a non-sequential order.

此刻我在想,aiohttp.ClientSession()是否会按顺序返回结果,因为它应该多次调用服务器,然后等待所有回复都到达。我原本期望结果不是按顺序返回。

Additionally, the rate of replies varied, but strangely enough, they still remained in sequence.

此外,回复的速率各不相同,但奇怪的是,它们仍然保持在顺序中。

I ran the below code multiple times:

我多次运行了以下代码:

async def main():
async with aiohttp.ClientSession() as session:
res_dict={}
for number in range(1, 100):
pokemon_url = f'https://pokeapi.co/api/v2/pokemon/{number}'
async with session.get(pokemon_url) as resp:
pokemon = await resp.json()
res_dict[number]=pokemon['id']
print(pokemon['id'])
for i in res_dict:
print(i, '=',res_dict[i])

asyncio.run(main())

And every time I ran it, I received the results in a perfectly ordered reply:

每次我运行它,我都以完全有序的方式收到了结果的回复:

1
2
3
.
.
.
98
99

And they were also correctly paired up with each of their dict Keys as well:

它们也与它们各自的字典键正确配对:

1=1
2=2
3=3
.
.
.
98=98
99=99

Would I be correct to assume that like asyncio.gather(), an aiohttp.ClientSession object's .get() method will make queries and receive them asynchronously, only listing them if they arrive in order? I also noticed that the rate of replies being received varied, and that could be a possible explanation as to why this is happening.

我是否可以合理地假设,类似于asyncio.gather(),aiohttp.ClientSession对象的.get()方法将异步地发出查询并接收它们,只有在它们按顺序到达时才将它们列出?我还注意到,接收到的回复速率各不相同,这可能是发生这种情况的可能解释。

英文:

I found myself wondering if aiohttp.ClientSession() would return results sequentially because it was supposed to call a server many times, and then wait for all of the replies to arrive. I was expecting the results to be returned in a non-sequential order.

Additionally, the rate of replies varied, but strangely enough, they still remained in sequence.

I ran the below code multiple times:

async def main():
    async with aiohttp.ClientSession() as session:
        res_dict={}
        for number in range(1, 100):
            pokemon_url = f'https://pokeapi.co/api/v2/pokemon/{number}'
            async with session.get(pokemon_url) as resp:
                pokemon = await resp.json()
                res_dict[number]=pokemon['id']
                print(pokemon['id'])
        for i in res_dict:
            print(i, '=',res_dict[i])

asyncio.run(main())

And every time I ran it, I received the results in a perfectly ordered reply:

1
2
3
.
.
.
98
99

And they were also correctly paired up with each of their dict Keys as well:

1=1
2=2
3=3
.
.
.
98=98
99=99

Would I be correct to assume that like asyncio.gather(), an aiohttp.ClientSession object's .get() method will make queries and receive them asynchronously, only listing them if they arrive in order? I also noticed that the rate of replies being received varied, and that could be a possible explanation as to why this is happening.

答案1

得分: 1

你的假设是正确的。通过进行相当多的修改,您可以通过创建一组类似以下方式的tasksgather中获取异步请求:

import aiohttp
import asyncio


async def main():

    res_dict = {}

    # URL列表
    urls = []
    for number in range(1, 20):
        pokemon_url = f'https://pokeapi.co/api/v2/pokemon/{number}'
        urls.append(pokemon_url)

    # 任务列表(包括gather)
    tasks = [asyncio.create_task(get_pokies(url)) for url in urls]
    responses = await asyncio.gather(*tasks)

    # 创建字典
    for i, response in enumerate(responses):
        res_dict[i] = response['id']
        
    print(res_dict)


async def get_pokies(url):
    '''用于请求的异步函数'''
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            return await response.json()


asyncio.run(main())

这将比问题中的原始代码快得多,因为现在请求是“并行”而不是“串行”进行的。

英文:

Your assumption is correct. With quite a bit of modification, you can get async requests in a gather by creating a set of tasks like this:

import aiohttp
import asyncio


async def main():

    res_dict = {}

    # list of urls
    urls = []
    for number in range(1,20):
        pokemon_url = f'https://pokeapi.co/api/v2/pokemon/{number}'
        urls.append(pokemon_url)

    # list of tasks (with the gather)
    tasks = [asyncio.create_task(get_pokies(url)) for url in urls]
    responses = await asyncio.gather(*tasks)

    # make the dict
    for i, response in enumerate(responses):
        res_dict[i] = response['id']
        
    print(res_dict)


async def get_pokies(url):
    ''' async func for the reqest '''
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            return await response.json()


asyncio.run(main())

This will be much faster than the original code in the question, since now the requests are made "in parallel" as opposed to "in series"...

huangapple
  • 本文由 发表于 2023年5月14日 04:00:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/76244656.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定