文章目錄
- 1. 單線程
- 2. 線程池ThreadPoolExecutor
1. 單線程
現在有1154張圖片需要順時針旋轉后保存到本地,一般使用循環1154次處理,具體代碼如下所示,img_paths中存儲1154個圖片路徑,該代碼段耗時約用97ms。
t1=time.time()
for imgpath in img_paths:img=cv2.imread(imgpath,0)img=cv2.rotate(img,cv2.ROTATE_90_CLOCKWISE)info=imgpath.split("/")parent,filename=info[-2],info[-1]filename=parent+"_"+filename.split(".")[0].zfill(5)+".jpg"dst_save_path=os.path.dirname(imgpath).replace(f"{sub}","result/")+filenamecv2.imwrite(dst_save_path,img)
t2=time.time()
print(t2-t1)
可以看到CPU運行狀態,只有一個在運行:
2. 線程池ThreadPoolExecutor
對于這種沒有數據交換的任務,可以使用多線程。python中有很多多線程、多進程的庫,這里試試線程池ThreadPoolExecutor。
這個庫核心有兩個:
- with ThreadPoolExecutor(max_workers=batch_size) as executor:創建一個上下文管理的執行器,并制定線程池中線程個數;
- executor.map(process_image, batch):process_image是執行的函數,接受一個路徑,batch是儲存多個路徑的列表,大小等于小于執行器的max_workers。這個方法會為batch中的每個圖像路徑啟動一個線程(最多同時運行max_workers數量的線程),并在每個線程中調用之前定義的process_image函數處理對應的圖像。map方法會等待所有線程完成后再繼續下一輪循環,確保每個批次內的圖像處理是并行且同步完成的。
下方的代碼耗時約37ms
import cv2
import os
from concurrent.futures import ThreadPoolExecutordef process_image(imgpath):# 讀取并旋轉圖像img = cv2.imread(imgpath, 0)img = cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE)# 分割路徑以獲取父目錄和文件名info = imgpath.split("/")parent, filename = info[-2], info[-1]# 重命名文件base_name = filename.split(".")[0]new_filename = f"{parent}_{base_name.zfill(5)}.jpg"# 構建保存路徑dst_save_path = os.path.dirname(imgpath).replace("sub", "result/") + new_filename# 保存處理后的圖像cv2.imwrite(dst_save_path, img)def batch_process_images(img_paths, batch_size=15):with ThreadPoolExecutor(max_workers=batch_size) as executor:for i in range(0, len(img_paths), batch_size):# 每次處理batch_size個圖像路徑batch = img_paths[i:i+batch_size]executor.map(process_image, batch)# 假設img_paths是包含所有圖像路徑的列表
img_paths = [...] # 這里填充實際的圖像路徑列表
batch_process_images(img_paths)
可以看到,15個cpu都被調用起來了