【问题标题】:What is the best way to send multiple HTTP requests in Python 3? [duplicate]在 Python 3 中发送多个 HTTP 请求的最佳方式是什么? [复制]
【发布时间】:2013-12-05 01:49:35
【问题描述】:

想法很简单:我需要并行发送多个 HTTP 请求。

我决定为此使用requests-futures 库,它基本上会产生多个线程。

现在,我有大约 200 个请求,但速度仍然很慢(在我的笔记本电脑上大约需要 12 秒)。我还使用回调来解析响应 json(如库文档中所建议的那样)。另外,是否有经验法则可以根据请求数计算出最佳线程数,有吗?

基本上,我想知道是否可以进一步加快这些请求的速度。

【问题讨论】:

  • 什么版本的python?您的 stdlib 选项从 2.7 到 3.3 发生了巨大变化。
  • 我打算建议使用 urllib + Threading 模块,但你链接到的包基本上做同样的事情。至于调整线程数,我在笔记本电脑(MacBook Pro,3.2 GHz 处理器,16 GB RAM)上运行了 25 个左右没有问题。
  • @roippi 我正在使用 python 3.3
  • @BenDundee 您发送了多少请求,性能如何?
  • @NikolayDerkach:我无法直接回答您的问题,但我有两个单独的示例,其中我使用了线程 POST 或 GET 之类的东西。最接近您的情况是使用 pyelasticsearch (它使用 requests 库)发布 JSON(查询)弹性索引。将这些查询线程化后,我通常会在 20-30 分钟内跨 5 个线程执行 15000 个 POST(我不能使用更多,或者我会收到来自平台人员的疯狂电子邮件)。有几百 KB 的有效负载。无论如何,我很难相信requests 的性能明显高于或低于urllib

标签: python multithreading http python-3.x concurrency


【解决方案1】:

由于您使用的是 python 3.3,我将推荐一个仅 python3 的 stdlib 解决方案:concurrent.futures

这是一个比直接处理threadingmultiprocessing 原语更高级别的接口。您将获得一个Executor 接口来处理池化和异步报告。

文档中有一个基本上直接适用于您的情况的示例,所以我将其放在这里:

import concurrent.futures
import urllib.request

URLS = #[some list of urls]

# Retrieve a single page and report the url and contents
def load_url(url, timeout):
    conn = urllib.request.urlopen(url, timeout=timeout)
    return conn.readall()

# We can use a with statement to ensure threads are cleaned up promptly
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
    # Start the load operations and mark each future with its URL
    future_to_url = {executor.submit(load_url, url, 60): url for url in URLS}
    for future in concurrent.futures.as_completed(future_to_url):
        url = future_to_url[future]
        try:
            data = future.result() 
            # do json processing here
        except Exception as exc:
            print('%r generated an exception: %s' % (url, exc))
        else:
            print('%r page is %d bytes' % (url, len(data)))

如果您愿意,可以将 urllib.request 呼叫替换为 requests 呼叫。出于显而易见的原因,我确实更喜欢requests

API 有点像这样:创建一堆 Future 对象,代表函数的异步执行。然后,您使用 concurrent.futures.as_completed 在您的 Future 实例上为您提供一个迭代器。当它们完成时,它将产生它们。

至于你的问题:

另外,是否有一个经验法则可以计算出最佳数量 线程作为请求数的函数,有吗?

经验法则,不。这取决于很多事情,包括您的互联网连接速度。我会说这并不取决于您的请求数量,更多取决于您运行的硬件。

幸运的是,调整max_workers kwarg 并自己测试非常容易。从 5 或 10 个线程开始,以 5 为增量递增。您可能会注意到性能在某个时候趋于平稳,然后随着添加额外线程的开销超过增加并行化的边际收益(这是一个词)开始下降.

【讨论】:

  • 让我说,我之前在我们的 AWS 机器上遇到过关于开放线程的个限制,但在我的笔记本电脑上没有。此处概述了该问题:alak.cc/2011/11/python-threaderror-cant-start-new.html
  • @roippi 你看过我在原始帖子中提到的 requests-futures 模块吗?它实现了几乎相同的代码。
  • @NikolayDerkach 不,我没有,但是看着它.. 呵呵!它基本上将上述内容包装到一个 API 调用中,这非常好。这样做的一个问题是,如果它很慢/行为不端,你就没有任何办法对其进行微调。例如,当出现问题时,您可以更轻松地检测上述代码。无论如何,祝你好运:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-02-07
  • 1970-01-01
  • 2021-02-25
  • 2021-07-12
  • 2013-06-01
  • 1970-01-01
  • 2019-06-29
相关资源
最近更新 更多