如何解决google-maps-services-python并发调用的连接池限制问题?
问题:google-maps-services-python并发调用static_map效率低下及连接池警告
我尝试用google-maps-services-python库的static_map方法,结合concurrent.futures.ThreadPoolExecutor实现并发调用,但即便设置了较大的max_workers,并行执行效率仍未达到预期,还收到如下警告:
WARNING:urllib3.connectionpool:Connection pool is full, discarding connection: maps.googleapis.com. Connection pool size: 10
根据Google官方文档,静态地图API最高支持30000 QPM(每分钟查询数),理论上可进行大量并行调用。我想了解是否能通过该库实现高效并发,还是应直接调用静态地图API的URL(https://maps.googleapis.com/maps/api/staticmap?parameters)而非使用该库,以下是我的相关代码:
import googlemaps import concurrent.futures client = googlemaps.Client(key='<MYKEY') # addresses = [ list of addresses to search with Google Maps API ] images_path = 'images/' def download_google_maps(filename, address): filename = filename + '.png' f = open(filename, 'wb') for chunk in client.static_map(size=(600, 600), center=address, zoom=20, format="png"): if chunk: f.write(chunk) f.close() message = 'Got Google Maps image in ' + filename print(message) return message def download_images(index, address): filename = images_path + str(index) download_google_maps(filename, address) with concurrent.futures.ThreadPoolExecutor(max_workers=20) as executor: futures = [] for i in range(len(addresses)): futures.append(executor.submit(download_images, i, addresses[i])) for future in concurrent.futures.as_completed(futures): try: result = future.result() except Exception as e: print(f'Exception: {e}')
解决方案
1. 调整客户端连接池大小
警告的根源是googlemaps库底层依赖的requests默认连接池大小只有10,当你开20个线程时,连接池不够用就会丢弃新连接。可以通过自定义session来修改连接池参数:
import googlemaps from requests.adapters import HTTPAdapter # 创建自定义session,设置更大的连接池 session = googlemaps.Client._create_session() # pool_maxsize设为和max_workers一致或更大,比如50 adapter = HTTPAdapter(pool_connections=50, pool_maxsize=50) session.mount("https://", adapter) # 用自定义session初始化客户端 client = googlemaps.Client(key='<MYKEY>', session=session)
这样连接池就能匹配你的线程数,避免连接被丢弃,直接提升并发效率。
2. 优化代码细节
- 用
with语句管理文件,自动关闭,比手动调用close()更安全简洁:
def download_google_maps(filename, address): filename = filename + '.png' with open(filename, 'wb') as f: for chunk in client.static_map(size=(600, 600), center=address, zoom=20, format="png"): if chunk: f.write(chunk) message = f'Got Google Maps image in {filename}' print(message) return message
- 用
executor.map简化任务提交代码,不用手动循环创建futures:
with concurrent.futures.ThreadPoolExecutor(max_workers=20) as executor: # 直接把index和address对应传入,自动分发任务 results = executor.map(download_images, range(len(addresses)), addresses) for result in results: try: print(result) except Exception as e: print(f'Exception: {e}')
3. 是否需要直接调用API URL?
完全没必要。googlemaps库已经帮你处理了参数编码、密钥管理、请求重试等繁琐细节,调整连接池后就能实现高效并发。直接调用URL反而需要自己处理这些逻辑,容易出现参数错误、签名问题或者重试机制缺失的情况。
内容的提问来源于stack exchange,提问作者Simone
相关产品推荐
相关产品推荐

