我正在尝试使用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左右急剧下降)raise_for_status()
抛出异常,然后通过将其作为警告打印来捕获此异常(不显示警告)print(response.status_code)
一直显示200 ,并没有发现任何例外。为了它的价值,我以前能够使用类似的方法在大约4秒内从S3下载~1500个文件,尽管文件的数量要小一些
我今天有空的时候会尝试的事情:
编辑:看起来线程的数量是稳定的,但是当性能开始变坏时,“空闲唤醒上升”的数量似乎从几百到几千。这个数字意味着什么,我可以用它来解决这个问题吗?
答案 0 :(得分:0)
这不是一个惊喜。
当线程数多于核心数时,您不会获得任何并行性。
您可以通过将问题简化为具有多个线程的单个核心来证明这一点。
会发生什么?您一次只能运行一个线程,因此操作系统上下文会切换每个线程以便为每个人提供一个转弯。一个线程起作用,其他线程一直在睡觉,直到它们被唤醒为止。在这种情况下,你不能比单线程更好。
你可能会做得更糟,因为每个线程(每个1MB)分配的上下文切换和内存也有价格。
阅读Amdahl's Law。