对多个 HTTP 请求的异步状态检查

Asynchronous status check on multiple HTTP requests

我有一个列表,其中包含数千个指向远程服务器上 images/videos 的 URL。类似于:

urls = ['https://foo.bar/baz.jpeg', 'https://foo.bar/jaz.mp4', ...]

通过获取那些 urls,一些响应以 404 Not Found 的形式出现,这没关系,因为服务器上的数据可能已过时并被删除.我想做的是快速确定哪个 url 会给我 404

当我打开浏览器并在地址栏中键入错误的 url 之一时,未找到 错误大约需要 200 毫秒才能被检索到。通过一些简单的计算,如果以异步方式进行,我预计 ~1.000 次调用将不会超过 4 秒即可完成。

但是,通过使用我认为在某种程度上合适的代码:

def async_check(urls):

    async def fetch(session, url):
        async with session.get(url) as response:
            if response.status != 200:
                return False
            else:
                return True

    async def run(urls):
        async with ClientSession() as session:
            return await asyncio.gather(*[fetch(session, url) for url in urls])

    return asyncio.get_event_loop().run_until_complete(run(urls))

经过的时间比较长,有时实际上是超时。

我认为这是由于列表中的 非错误 url 造成的,它指向可能需要很长时间才能加载的图像和视频响应对象并最终消耗大量时间才能完成任务。

在思考如何实现 404s 的验证之后,我得出了一个大致如下所示的流程:

对于每个 url,使用 get 方法异步获取它,并异步休眠相对较长的时间(例如 1 秒)。休眠完成后,尝试查看响应是否“就绪”,如果是,如果状态代码为 404(或不同于 200)。如果在休眠后,响应没有“准备好”,那么我会假设这是由于负载过重 image/video 并认为它 非故障 .

由于每次调用的等待时间上限为 1 秒,我希望它 运行 对于一堆 url 来说会相对较快。

这会被认为是解决这个问题的巧妙方法,还是有更聪明的方法?

I believe that's due to the non-faulty urls inside the list, which point to images and videos that can take a long time to load as a response object and end up consuming a lot of time in order to complete the task.

很难预先判断这是否真的是真的,但您当然可以通过添加代码来测试它 time.time() 来测量每个请求所用的时间并打印其状态。

请注意,除非您 await response.read() 或等效的,响应 body 不会被客户端“加载”,只有 header 是。不过,某些 non-faulty URL 很可能需要很长时间才能 return header。也有可能是一些错误的需要很长时间才能return错误状态,也许是那些你没有手动检查的。 asyncio.gather() 将与列表中最长的 URL 一样长,因此如果您有数千个 URL,至少其中一些必然会滞后。

但假设你的前提是正确的,你可以通过将 fetch 包装在 wait_for:

中来实现限制
    async def fetch_with_limit(session, url):
        try:
            return await asyncio.wait_for(fetch(session, url), 1)
        except asyncio.TimeoutError:
            return True  # took more than 1s, probably non-faulty

现在您可以使用 fetch_with_limit 而不是 fetch