编辑:我使用的是 Python 3.5.0,所以 map()
将返回一个迭代器而不是 list
,这与Python 2.x
我有一个单元列表,我正在对所有单元调用 REST api 以返回有关它们的更多数据。我正在使用 map()
来执行此操作,但是当我尝试将该映射转换为列表时,程序卡在那里并且不会继续(在我运行它和调试它时)
data = list(map(lambda product: client.request(units_url + "/" + product), units))
起初我认为可能是因为调用 api 太快导致了问题,但是当我手动遍历 map (没有将其转换为列表)并打印时,一切正常:
data = map(lambda product: client.request(units_url + "/" + product), units)
for item in data:
print(item) # <-- this works just fine for the entire map
有人知道我为什么会出现这种行为吗?
最佳答案
当你list
- 确定 map
,这意味着每个请求都按顺序发送,等待完成,然后存储到生成的 list
中。 .如果您要发送 1000 个请求,这意味着每个请求都必须在 list
之前按顺序一个接一个地完成。已构建,您会看到第一个结果;它是完全同步的。
您(几乎)立即在直接 map
中得到结果迭代案例,因为它一次只发出一个请求;它不是等待 1000 个请求,而是等待 1 个,您处理该结果,然后等待另一个,依此类推。
如果目标是最小化延迟,请查看 multiprocessing.Pool.imap
(或在 multiprocessing.dummy
中实现的基于线程的池版本;线程可以是并行网络 I/O 请求的理想选择,并且不需要为 IPC 挑选数据)。随着Pool
的 map
, imap
, 或 imap_unordered
方法(根据您的需要选择一种),请求将被异步分派(dispatch),一次分派(dispatch)多个(取决于您选择的工作人员数量)。如果你绝对必须有一个 list
, Pool.map
通常会更快地构建它;如果你可以直接迭代而不关心结果的顺序,Pool.imap_unordered
将以他们满意的任何顺序以工作人员获得结果的速度尽快为您提供结果。普通 map
没有 Pool
没有给你带来任何神奇的性能优势(列表理解实际上通常运行得更快),所以使用 Pool
.
最快结果的简单示例代码:
import multiprocessing.dummy as multiprocessing # Import thread based version of library; for network I/O should work fine
with multiprocessing.Pool(8) as pool: # Pool of eight worker threads
for item in pool.imap_unordered(lambda product: client.request(units_url + "/" + product), units):
print(item)
如果你真的需要,你可以使用Pool.map
并存储到真实的 list
,并假设您有足够的带宽来运行八个并行请求(或者无论您为池配置多少工作人员),这应该(大致)划分时间来完成 map
八点。
关于python将 map 转换为列表需要很长时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33024007/