上一章节,我们用wxPython给图片格式转换器写了一个简单的GUI,测试时用的是几百张小图片,我们再来测试一下批量处理照片,照片的文件比较大,每张都有好几M。

果真出问题了,界面卡死了。目标文件夹有新的图片还在不断生成,说明程序仍在运行,但是界面已经卡死。在处理复杂的任务的时候,不能把任务写在UI线程里,需要单独使用线程处理。代码修改如下:
# 点击转换格式按钮,触发此方法,获取图片输入输出路径和图片输出类型,转换图片。
def ConvertButtonEvent(self, event):
srcPath = self.srcPathTextCtrl.GetValue() # 原图片路径
dstPath = self.dstPathTextCtrl.GetValue() # 目标图片路径
if srcPath == '':
wx.MessageBox('请选择图片输入路径', '消息', wx.OK | wx.ICON_INFORMATION)
return
if dstPath == '':
wx.MessageBox('请选择图片输出路径', '消息', wx.OK | wx.ICON_INFORMATION)
return
ext = self.extCombobox.GetValue() # 目标图片类型
# 用新线程执行处理图片的任务,并使用元组做为参数传入原图片路径、目标图片路径、目标图片类型
_thread.start_new_thread(self.process_image, (srcPath, dstPath, ext,))
# 处理图片
def process_image(self, srcPath, dstPath, ext):
file_list = file_walk(srcPath)
for srcImagePath in file_list:
print(srcImagePath)
if os.path.getsize(srcImagePath) == 0:
continue
try:
image = Image.open(srcImagePath)
image = ImageOps.exif_transpose(image)
srcImageName = os.path.split(srcImagePath)[1]
dstImageName = os.path.splitext(srcImageName)[0] + ext
dstImagePath = os.path.join(dstPath, dstImageName)
image.save(dstImagePath)
self.tip.SetLabel('正在转换:%s' % srcImagePath)
except Exception as e:
print(e)
self.tip.SetLabel('转换完成')

好了,界面不会卡死了,问题解决。
但是感觉这个转换速度是真让人捉急!有什么好的办法让它能加快速度呢?对了,既然用了线程,为什么不用多线程来处理呢?继续修改代码
# 用新线程执行处理图片的任务,并使用元组做为参数传入原图片路径、目标图片路径、目标图片类型
# _thread.start_new_thread(self.process_image, (srcPath, dstPath, ext,))
thread_pool = ThreadPoolExecutor(4)
file_list = file_walk(srcPath)
for srcImagePath in file_list:
# print(srcImagePath)
if os.path.getsize(srcImagePath) == 0:
continue
thread_pool.submit(self.process_image, srcImagePath, dstPath, ext)
# 处理图片
def process_image(self, srcImagePath, dstPath, ext):
print(srcImagePath)
try:
image = Image.open(srcImagePath)
image = ImageOps.exif_transpose(image)
srcImageName = os.path.split(srcImagePath)[1]
dstImageName = os.path.splitext(srcImageName)[0] + ext
dstImagePath = os.path.join(dstPath, dstImageName)
image.save(dstImagePath)
self.tip.SetLabel('正在转换:%s' % srcImagePath)
except Exception as e:
print(e)
这里用到了线程池
thread_pool = ThreadPoolExecutor(4)
其中4代表线程池创建了4个线程,也就是说可以同时处理4张图片。那么是不是创建线程越多越好呢?其实并不是的,经过测试我发现处理线程数跟CPU的核心数有关,当创建的线程数越过CPU核心数时,速度也不会提升了。据说Python的多线程实际上并不能真正利用多核,所以如果使用多线程实际上还是在一个核上做并发处理。不过,如果使用多进程就可以真正利用多核,因为各进程之间是相互独立的,不共享资源,可以在不同的核上执行不同的进程,达到并行的效果。
我们这里把线程数设置为CPU的核心数。到设备管理器和任务管理器里查看一下CPU的核心数


import os
print(os.cpu_count())

修改一下代码
thread_pool = ThreadPoolExecutor(max_workers=os.cpu_count())
现在是不是快多了!