python 多进程处理图像,充分利用CPU

默认情况下,Python程序使用一个CPU以单个进程运行。不过如果你是在最近几年配置的电脑,通常都是四核处理器,也就是有8个CPU。这就意味着在你苦苦等待Python脚本完成数据处理工作时,你的电脑其实有90%甚至更多的计算资源就在那闲着没事干!

得益于Python的 concurrent.futures 模块,我们只需3行代码,就能将一个普通数据处理脚本变为能并行处理数据的脚本!

普通Python处理数据方法

比方说,我们有一个全是图像数据的文件夹里面含有2000张彩色图片,用Python将每张图像灰度化。

import glob
import cv2
import concurrent.futures
import time

def process_image(filename):
    # do sth here
    img = cv2.imread(filename)
    img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    return img
if __name__ == "__main__":
    start = time.time()
    i = 1
    filenames= glob.glob("train/*.jpg")
    for filename in filenames:
        img = process_image(filename)
        cv2.imwrite("result/" + str(i) + '.jpg', img)
        i += 1
    print(time.time()-start)

  这种方法所用的时间为220秒左右!

试试创建多进程

多线程和多进程模块在使用的时候, start() 方法和 join() 方法不能省, 有时候还需要使用 Queue, 随着需求越来越复杂, 如果没有良好的设计抽象出这部分功能,
代码量会越来越多,debug 的难度也会越来越大。concurrent.futures 模块可以把这些步骤抽象, 这样我们就不需要关注这些细节。
concurrent.futures主要使用的就是两个类,多线程:ThreadPoolExecutor多进程:ProcessPoolExecutor
Executor类不能直接使用,而应该通过其子类TreadPoolExecutor,ProcessPoolExecutor来调用其方法。
注意:创建进程要在
if __name__ == "__main__":下面,否则报错
import time
import glob
import cv2
import concurrent.futures
def process_image(filename):
    img = cv2.imread(filename)
    img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    return img
if __name__ == "__main__":
    start = time.time()
    i = 1
    filenames= glob.glob("train/*.jpg")
    p = concurrent.futures.ProcessPoolExecutor()
  #p.map()函数调用时需要输入辅助函数和待处理的数据列表。
  #这个函数能帮我完成所有麻烦的工作,包括将列表分为多个子列表、将子列表发送到每个子进程、运行子进程以及合并结果等
    result = p.map(process_image, filenames)
    #p.shutdown(wait=True)
    for processedimg in result:
        cv2.imwrite("result/"+str(i)+'.jpg',processedimg)
        i+=1
    print(time.time()-start)

  这种方法处理2000幅图片时间大约108秒,速度快了一半

posted @ 2019-12-09 16:15  奥布莱恩  阅读(1683)  评论(0编辑  收藏  举报