gpt4 book ai didi

multithreading - 多线程 HTTP GET 请求在大约 900 次下载后严重减慢

转载 作者:行者123 更新时间:2023-12-03 12:44:51 38 4
gpt4 key购买 nike

我正在尝试使用 requests_futures 从 Amazon S3 下载大约 3,000 个文件(每个文件的大小可能为 3 MB)。 ,但下载速度在大约 900 后严重减慢,实际上开始运行速度比基本的 for 循环慢。
我似乎没有耗尽内存或 CPU 带宽。然而,看起来我机器上的 Wifi 连接速度几乎没有变慢:我从几千个数据包/秒下降到只有 3-4 个。最奇怪的是,在 Python 进程退出并重新启动 wifi 适配器之前,我无法加载任何网站。
到底是什么原因导致了这种情况,我该如何调试它?
如果有帮助,这是我的 Python 代码:

import requests
from requests_futures.sessions import FuturesSession
from concurrent.futures import ThreadPoolExecutor, as_completed

# get a nice progress bar
from tqdm import tqdm

def download_threaded(urls, thread_pool, session):
futures_session = FuturesSession(executor=thread_pool, session=session)
futures_mapping = {}
for i, url in enumerate(urls):
future = futures_session.get(url)
futures_mapping[future] = i

results = [None] * len(futures_mapping)

with tqdm(total=len(futures_mapping), desc="Downloading") as progress:
for future in as_completed(futures_mapping):
try:
response = future.result()
result = response.text
except Exception as e:
result = e
i = futures_mapping[future]
results[i] = result
progress.update()

return results

s3_paths = [] # some big list of file paths on Amazon S3
def make_s3_url(path):
return "https://{}.s3.amazonaws.com/{}".format(BUCKET_NAME, path)

urls = map(make_s3_url, s3_paths)
with ThreadPoolExecutor() as thread_pool:
with requests.session() as session:
results = download_threaded(urls, thread_pool, session)
使用我尝试过的各种方法进行编辑:
  • time.sleep(0.25)每一次之后 future.result() (性能在 900 左右急剧下降)
  • 4 个线程而不是默认的 20 个(性能逐渐下降,但仍然基本上没有下降)
  • 1 个线程(性能在 900 左右急剧下降,但间歇性恢复)
  • ProcessPoolExecutor 而不是 ThreadPoolExecutor(性能在 900 左右急剧下降)
  • 调用 raise_for_status()每当状态大于 200 时抛出异常,然后通过将其打印为警告(不出现警告)来捕获此异常
  • 在完全不同的网络上使用以太网而不是 wifi(无变化)
  • 在普通请求 session 中创建 future 而不是使用 FutureSession(这是我最初所做的,并在尝试解决问题时发现 requests_futures)
  • 仅运行下载失败点附近的一小部分文件(例如文件 850 到文件 950)——这里的性能很好,print(response.status_code)一路显示200,没有捕捉到异常。

  • 就其值(value)而言,我以前能够使用类似的方法在大约 4 秒内从 S3 下载约 1500 个文件,尽管文件要小一个数量级
    今天有时间我会尝试的事情:
  • 使用 for 循环
  • 在 shell 中使用 Curl
  • 在 shell 中使用 Curl + Parallel
  • 使用 urllib2

  • 编辑:看起来线程数是稳定的,但是当性能开始变差时,“空闲唤醒”的数量似乎从几百个飙升到几千个。这个数字是什么意思,我可以用它来解决这个问题吗?
    来自 future 的编辑 2:我从来没有弄清楚这个问题。我没有在一个应用程序中完成所有工作,而是将文件列表分块,并在单独的终端窗口中使用单独的 Python 调用运行每个块。丑但有效!问题的原因永远是个谜,但我认为这是我当时工作机器网络堆栈深处的某种问题。

    最佳答案

    这并不意外。

    当线程数多于内核数时,您不会获得任何并行性。

    您可以通过将问题简化为具有多个线程的单个内核来证明这一点。

    发生什么了?一次只能运行一个线程,因此操作系统上下文会切换每个线程,让每个人都可以轮流使用。一个线程工作,其他线程休眠,直到他们被唤醒依次做他们的工作。在这种情况下,你不能比单线程做得更好。

    您可能会做得更糟,因为为每个线程(每个 1MB)分配的上下文切换和内存也有代价。

    阅读 Amdahl's Law .

    关于multithreading - 多线程 HTTP GET 请求在大约 900 次下载后严重减慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40274072/

    38 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com