Skip to content

Can't make 40k requests from client to server #1142

Closed
@ericfrederich

Description

@ericfrederich

Long story short

I cannot make 40k requests using a semaphore to limit concurrency.

This is based on code from here though actual code is in-lined below.

Expected behaviour

I should be able to make unlimited requests from an aiohttp client to an aiohttp server.

Actual behaviour

Exceptions are thrown. See below.

I was able to make 1 million requests to a locally running httpbin server running under gunicorn.

I dug into it a bit and wondered if ayncio it self didn't like having 40k tasks running, so I faked out the response by modifying aiohttp/client.py with the following code and make ClientSession.get() return this FakeResponseContextManager. It worked just fine when I did this.

So the problem isn't that I'm creating 40,000 or 1,000,000 tasks. Python's asyncio seems to handle that many tasks just fine. Something blows up with this aiohttp client in conjunction with the aiohttp server (again, because serving httpbin test server worked just fine too).

class FakeResponse:
    def __init__(self, url):
        self._url = url

    async def read(self):
        await asyncio.sleep(0.01)
        return self._url

class FakeResponseContextManager:
    def __init__(self, url):
        self._url = url

    async def __aenter__(self):
        await asyncio.sleep(0.01)
        return FakeResponse(self._url)

    async def __aexit__(self, exc_type, exc, tb):
        await asyncio.sleep(0.01)

Steps to reproduce

  • run the server
  • run the client
  • see exceptions

server

#!/usr/bin/env python3

from aiohttp import web

async def handle(request):
    name = request.match_info.get('name', "Anonymous")
    text = "Hello, " + name
    return web.Response(body=text.encode('utf-8'))

app = web.Application()
app.router.add_route('GET', '/{name}', handle)

web.run_app(app)

client

#!/usr/bin/env python3

import random
import asyncio
from aiohttp import ClientSession

async def fetch(url):
    async with ClientSession() as session:
        async with session.get(url) as response:
            print(url)
            return await response.read()


async def bound_fetch(sem, url):
    # getter function with semaphore
    async with sem:
        await fetch(url)


async def run(loop,  r):
    url = "http://localhost:8080/{}"
    tasks = []
    # create instance of Semaphore
    sem = asyncio.Semaphore(10)
    for i in range(r):
        # pass Semaphore to every GET request
        task = asyncio.ensure_future(bound_fetch(sem, url.format(i)))
        tasks.append(task)

    responses = asyncio.gather(*tasks)
    await responses

number = 40000
loop = asyncio.get_event_loop()

future = asyncio.ensure_future(run(loop, number))
loop.run_until_complete(future)

Your environment

  • Linux Mint 18 (based on Ubuntu 16.04)
  • Out of the box Python 3.5.2
  • aiohttp installed within virtualenv

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions