我的目标是对具有数百个并发请求的外部 API 进行多处理请求。我使用Pool
函数执行此操作,该功能工作正常,但是对于 64 个工作线程,我的 RAM 使用率为 25Gb(与工作线程数量成正比(,这对于简单的 http 请求来说似乎很高。
如何将 RAM 使用量降至最低,以便我可以启动数百个工作线程?
我的假设是 Pool 函数在每个工作线程中复制整个进程内存。我怎样才能避免这种情况?
代码:
from multiprocessing import Pool
def get_results(self, query):
self.data["query"] = query["query"]
results = requests.post(url_to_external_api_with_query_data).json()
return {"results":results, "original_query":query["original_query"], "original_query_string":query["query"]}
def multiprocess_results(self, queries):
pool = Pool(64)
results_all = pool.map(self.get_results, queries)
pool.close()
pool.join()
首先,如果您要将请求发送到 I/O 绑定的 HTTPS,那么您可能需要考虑使用多线程而不是多处理,这应该可以立即解决您的内存问题。 此外,多处理的事情是创建拥有其Python解释器副本的重复进程。因此,多个工作线程代码并行运行,因此您使用的内存总量应取决于您正在执行的操作。
对于多处理和多线程,我经常推荐 concurent.futures 我推荐它的原因是它根据可以腾出的内存量自动为多处理任务分配工作线程(这可以在您喜欢时覆盖(。
使用此模块有时比使用典型的多处理模块更容易,因为您可以用更少的代码获得更多。
from concurrent.futures import ProcessPoolExecutor
....
with ProcessPoolExecutor() as executor:
executor.submit(self.get_results, queries)
同样,由于这是发送HTTPS请求,因此它是一个I/O绑定操作,您应该考虑使用多线程。此模块中的两种操作的工作方式相似
from concurrent.futures import ThreadPoolExecutor
....
with ThreadPoolExecutor() as executor:
executor.submit(self.get_results, queries)