0

I am building a FastAPI server for an image classification model. The API takes in image urls and downloads them concurrently using httpx. I want to limit the number of concurrent downloads across the server using asyncio.Semaphores. I tried creating a sempahore as a classifier attribute as I need it shared among all requests. But I get the error: got Future <Future pending created at /usr/lib/python3.9/asyncio/base_events.py:424> attached to a different loop.

Here is my code:

 
# classifier.py

import asyncio
import httpx


class Classifier():
    def __init__(
        self,
        concurrency_limit,
    ) -> None:
        self.client = httpx.AsyncClient()
        self.semaphore = asyncio.Semaphore(concurrency_limit)

    async def download_async(self, url):
        async with self.semaphore:
            response = await self.client.get(url)

        return await response.aread()

    async def run(
        self, image_urls
    ):
        image_list = await asyncio.gather(
            *[self.download_async(url) for i, url in enumerate(image_urls)]
        )

        # Infer Images
        pass



# api.py
from fastapi import FastAPI

server = FastAPI()

classifier = Classifier(concurrency_limit=5)

@server.post("/")
async def index(urls):
    results = await classifier.run(urls)

Answers online mention creating a semaphore within a running Event loop, but if I create it within run() a new semaphore is created for every request. i.e each request allows 5 downloads concurrently. How do I use the same semaphore across all requests?

  • 1
    I think you should try move your `classifier = Classifier(concurrency_limit=5)` into a `startup` event handler https://fastapi.tiangolo.com/advanced/events/#startup-event see also https://asgi.readthedocs.io/en/latest/specs/lifespan.html#startup-receive-event – Anentropic Jun 13 '22 at 11:27
  • Yep. Just tried that a while ago seems to be working fine. Although I have to declare `classifier` as a global variable. Is there any way I could avoid using global variables? – Lezwon Castellino Jun 13 '22 at 12:17
  • 1
    it might be a use case for FastAPI's dependency injection https://fastapi.tiangolo.com/tutorial/dependencies/ – Anentropic Jun 13 '22 at 15:46
  • Hey @Anentropic, any idea how to write offline test cases for the classifier? I'm not sure how to correctly mock httpx.get for the dependency. – Lezwon Castellino Jun 23 '22 at 10:44
  • 1
    try this https://github.com/lundberg/respx – Anentropic Jun 23 '22 at 11:48

0 Answers0