如何向concurrent.futures.ThreadPoolExecutor.map()传递多个参数
问题根源
- 你之前调用
executor.map时传入的可迭代对象(images, path)只有2个元素,第一个是完整的URL列表,第二个是路径字符串,导致down函数接收到的第一个参数是列表而非单个URL,执行逻辑完全错误。 - 你的
down函数中使用chdir修改进程全局工作目录,属于线程不安全操作,多个线程同时修改会导致保存路径混乱,甚至程序异常。
前置优化:修正下载函数的线程安全问题
不要通过修改全局工作目录指定保存路径,直接用wget.download自带的out参数指定输出路径即可:
from wget import download import os def down(url, path=None): """Download image urls. :param url: url of the image(mandatory) :param path: path to be downloaded images(optional) """ try: if path: # 直接指定输出路径,不修改全局工作目录,线程安全 download(url, out=os.path.join(path, os.path.basename(url))) else: download(url) except (ValueError, Exception): # 捕获下载异常跳过无效资源 pass
两种向executor.map传多参数的实现方式
方法1:利用executor.map原生多可迭代参数特性
executor.map支持传入多个可迭代对象,函数的每个参数对应一个可迭代对象,我们可以用itertools.repeat生成和URL列表长度一致的路径迭代对象:
import concurrent.futures import itertools images = [] # 替换为你的图片URL列表 path = "/home/dead101/Downloads" # 提前创建保存目录,避免下载时报路径不存在 os.makedirs(path, exist_ok=True) with concurrent.futures.ThreadPoolExecutor() as executor: # 第一个可迭代对象对应down的第一个参数url,第二个对应down的第二个参数path executor.map(down, images, itertools.repeat(path))
方法2:参数打包成元组后拆包
如果更习惯用打包传参的方式,需要将每个URL和路径配对,生成和URL数量一致的元组序列:
import concurrent.futures images = [] path = "/home/dead101/Downloads" os.makedirs(path, exist_ok=True) with concurrent.futures.ThreadPoolExecutor() as executor: # 每个元素是(url, path)的元组,对应每次调用down的两个参数 args = ((url, path) for url in images) executor.map(lambda p: down(*p), args)
内容的提问来源于stack exchange,提问作者Aesha Amoli
相关产品推荐
相关产品推荐

