如何将线程内调用函数的返回值保存到循环外的公共列表中
多线程收集process_folders返回值的实现方案
Python标准库的threading.Thread默认不会返回目标函数的执行结果,你可以用以下3种常见方案实现结果收集:
方案1:传入可变公共容器收集结果
列表、字典这类可变对象可以直接在线程间共享,CPython中列表的append操作是原子性的,简单场景下无需额外加锁:
import time import glob from threading import Thread def compare_two_images(image1, image2): # 你的比对逻辑 return "相似图片地址" if "相似判断条件" else None def process_folders(path_to_folder, result_list): print("Current Folder: " + path_to_folder) start_time = time.time() # 修正原代码笔误:原参数是path_to_folder,不是folder input_arr = glob.glob(path_to_folder+'/*') res = [compare_two_images(input_arr[i], input_arr[i + 1]) for i in range(len(input_arr) - 1)] print("Folder completed with " + str(time.time() - start_time)) # 把结果加入公共列表,不需要return result_list.append({ "folder_path": path_to_folder, "compare_result": res }) # 公共结果列表 all_results = [] threads = [] # 你的子文件夹列表 folder_with_subfolders = ["./test1", "./test2"] for folder in folder_with_subfolders: # 把公共列表作为参数传入线程 threads.append(Thread(target=process_folders, args=(folder, all_results))) threads[-1].start() for thread in threads: thread.join() # 所有线程执行完成后,all_results里就有全部结果了 print(all_results)
方案2:使用concurrent.futures.ThreadPoolExecutor(更推荐)
这个高阶库会自动管理线程,且可以直接获取每个线程的返回值,不需要手动维护公共容器:
import time import glob from concurrent.futures import ThreadPoolExecutor def compare_two_images(image1, image2): return "相似图片地址" if "相似判断条件" else None def process_folders(path_to_folder): print("Current Folder: " + path_to_folder) start_time = time.time() input_arr = glob.glob(path_to_folder+'/*') res = [compare_two_images(input_arr[i], input_arr[i + 1]) for i in range(len(input_arr) - 1)] print("Folder completed with " + str(time.time() - start_time)) # 直接返回结果即可 return { "folder_path": path_to_folder, "compare_result": res } folder_with_subfolders = ["./test1", "./test2"] all_results = [] # max_workers设置最大同时执行的线程数,可根据硬件调整 with ThreadPoolExecutor(max_workers=4) as executor: # 提交所有任务,得到future对象列表 futures = [executor.submit(process_folders, folder) for folder in folder_with_subfolders] # 逐个获取返回值 for future in futures: all_results.append(future.result()) print(all_results)
方案3:自定义Thread子类存储返回值
重写Thread的run方法,把返回值存到实例属性中,线程执行结束后直接读取属性即可:
import time import glob from threading import Thread def compare_two_images(image1, image2): return "相似图片地址" if "相似判断条件" else None # 自定义Thread子类 class ResultThread(Thread): def run(self): self.result = None if self._target is not None: self.result = self._target(*self._args, **self._kwargs) def process_folders(path_to_folder): print("Current Folder: " + path_to_folder) start_time = time.time() input_arr = glob.glob(path_to_folder+'/*') res = [compare_two_images(input_arr[i], input_arr[i + 1]) for i in range(len(input_arr) - 1)] print("Folder completed with " + str(time.time() - start_time)) return res folder_with_subfolders = ["./test1", "./test2"] threads = [] for folder in folder_with_subfolders: threads.append(ResultThread(target=process_folders, args=(folder,))) threads[-1].start() all_results = [] for thread in threads: thread.join() # 读取线程实例的result属性拿到返回值 all_results.append(thread.result) print(all_results)
注意事项
如果你的图片比对逻辑是CPU密集型运算,Python多线程受GIL(全局解释器锁)限制无法真正并行,不会有明显提速,建议换成多进程实现,上述方案换成multiprocessing相关API即可通用。
内容的提问来源于stack exchange,提问作者ison
相关产品推荐
相关产品推荐

